diff --git a/package.json b/package.json index 70d3c7f6..a72e43d1 100644 --- a/package.json +++ b/package.json @@ -42,9 +42,10 @@ "@babel/runtime": "^7.10.3", "@types/aria-query": "^4.2.0", "aria-query": "^4.2.2", + "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.1", - "pretty-format": "^26.4.2", - "chalk": "^4.1.0" + "lz-string": "^1.4.4", + "pretty-format": "^26.4.2" }, "devDependencies": { "@testing-library/jest-dom": "^5.10.1", @@ -78,4 +79,4 @@ "url": "https://github.com/testing-library/dom-testing-library/issues" }, "homepage": "https://github.com/testing-library/dom-testing-library#readme" -} \ No newline at end of file +} diff --git a/src/__tests__/screen.js b/src/__tests__/screen.js index 2496e09f..76aa51a1 100644 --- a/src/__tests__/screen.js +++ b/src/__tests__/screen.js @@ -1,5 +1,5 @@ import {screen} from '..' -import {renderIntoDocument} from './helpers/test-utils' +import {render, renderIntoDocument} from './helpers/test-utils' // Since screen.debug internally calls getUserCodeFrame, we mock it so it doesn't affect these tests jest.mock('../get-user-code-frame', () => ({ @@ -21,6 +21,49 @@ test('exposes queries that are attached to document.body', async () => { expect(screen.queryByText(/hello world/i)).not.toBeNull() }) +test('logs Playground URL that are attached to document.body', () => { + renderIntoDocument(`
hello world
`) + screen.logTestingPlaygroundURL() + expect(console.log).toHaveBeenCalledTimes(1) + expect(console.log.mock.calls[0][0]).toMatchInlineSnapshot(` + "Open this URL in your browser + + https://testing-playground.com/#markup=DwEwlgbgfAFgpgGwQewAQHdkCcEmAenGiA" + `) +}) + +test('logs messsage when element is empty', () => { + screen.logTestingPlaygroundURL(document.createElement('div')) + expect(console.log).toHaveBeenCalledTimes(1) + expect(console.log.mock.calls[0][0]).toMatchInlineSnapshot( + `"The provided element doesn't have any children."`, + ) +}) + +test('logs messsage when element is not a valid HTML', () => { + screen.logTestingPlaygroundURL(null) + expect(console.log).toHaveBeenCalledTimes(1) + expect(console.log.mock.calls[0][0]).toMatchInlineSnapshot( + `"The element you're providing isn't a valid DOM element."`, + ) + console.log.mockClear() + screen.logTestingPlaygroundURL({}) + expect(console.log).toHaveBeenCalledTimes(1) + expect(console.log.mock.calls[0][0]).toMatchInlineSnapshot( + `"The element you're providing isn't a valid DOM element."`, + ) +}) + +test('logs Playground URL that are passed as element', () => { + screen.logTestingPlaygroundURL(render(`

Sign up

`).container) + expect(console.log).toHaveBeenCalledTimes(1) + expect(console.log.mock.calls[0][0]).toMatchInlineSnapshot(` + "Open this URL in your browser + + https://testing-playground.com/#markup=DwCwjAfAyglg5gOwATAKYFsIFcAOwD0GEB4EQA" + `) +}) + test('exposes debug method', () => { renderIntoDocument( `multi-test
multi-test
`, diff --git a/src/screen.js b/src/screen.js index f6768c6b..5cbdd2de 100644 --- a/src/screen.js +++ b/src/screen.js @@ -1,23 +1,51 @@ +import {compressToEncodedURIComponent} from 'lz-string' import * as queries from './queries' import {getQueriesForElement} from './get-queries-for-element' import {logDOM} from './pretty-dom' +import {getDocument} from './helpers' + +function unindent(string) { + // remove white spaces first, to save a few bytes. + // testing-playground will reformat on load any ways. + return string.replace(/[ \t]*[\n][ \t]*/g, '\n') +} + +function encode(value) { + return compressToEncodedURIComponent(unindent(value)) +} + +function getPlaygroundUrl(markup) { + return `https://testing-playground.com/#markup=${encode(markup)}` +} const debug = (element, maxLength, options) => Array.isArray(element) ? element.forEach(el => logDOM(el, maxLength, options)) : logDOM(element, maxLength, options) +const logTestingPlaygroundURL = (element = getDocument().body) => { + if (!element || !('innerHTML' in element)) { + console.log(`The element you're providing isn't a valid DOM element.`) + return + } + if (!element.innerHTML) { + console.log(`The provided element doesn't have any children.`) + return + } + console.log( + `Open this URL in your browser\n\n${getPlaygroundUrl(element.innerHTML)}`, + ) +} + +const initialValue = {debug, logTestingPlaygroundURL} export const screen = typeof document !== 'undefined' && document.body - ? getQueriesForElement(document.body, queries, {debug}) - : Object.keys(queries).reduce( - (helpers, key) => { - helpers[key] = () => { - throw new TypeError( - 'For queries bound to document.body a global document has to be available... Learn more: https://testing-library.com/s/screen-global-error', - ) - } - return helpers - }, - {debug}, - ) + ? getQueriesForElement(document.body, queries, initialValue) + : Object.keys(queries).reduce((helpers, key) => { + helpers[key] = () => { + throw new TypeError( + 'For queries bound to document.body a global document has to be available... Learn more: https://testing-library.com/s/screen-global-error', + ) + } + return helpers + }, initialValue) diff --git a/types/screen.d.ts b/types/screen.d.ts index 2594f5be..bc77683f 100644 --- a/types/screen.d.ts +++ b/types/screen.d.ts @@ -1,17 +1,22 @@ -import { BoundFunctions, Queries } from './get-queries-for-element'; -import * as queries from './queries'; -import { OptionsReceived } from 'pretty-format'; +import {BoundFunctions, Queries} from './get-queries-for-element' +import * as queries from './queries' +import {OptionsReceived} from 'pretty-format' export type Screen = BoundFunctions & { - /** - * Convenience function for `pretty-dom` which also allows an array - * of elements - */ - debug: ( - element?: Element | HTMLDocument | Array, - maxLength?: number, - options?: OptionsReceived, - ) => void; -}; + /** + * Convenience function for `pretty-dom` which also allows an array + * of elements + */ + debug: ( + element?: Element | HTMLDocument | Array, + maxLength?: number, + options?: OptionsReceived, + ) => void + /** + * Convenience function for `Testing Playground` which logs URL that + * can be opened in a browser + */ + logTestingPlaygroundURL: (element?: Element | HTMLDocument) => void +} -export const screen: Screen; +export const screen: Screen