From 3a581d5626b5a974950520094a569a63ea3b5faa Mon Sep 17 00:00:00 2001 From: Patrick Hulce Date: Thu, 14 Feb 2019 18:15:06 -0600 Subject: [PATCH] feat: add pptr-testing-library docs --- docs/pptr-testing-library/intro.md | 81 ++++++++++++ website/pages/en/index.js | 5 + website/pages/en/pptr.js | 159 +++++++++++++++++++++++ website/static/img/puppeteer-275x275.png | Bin 0 -> 21288 bytes 4 files changed, 245 insertions(+) create mode 100644 docs/pptr-testing-library/intro.md create mode 100644 website/pages/en/pptr.js create mode 100644 website/static/img/puppeteer-275x275.png diff --git a/docs/pptr-testing-library/intro.md b/docs/pptr-testing-library/intro.md new file mode 100644 index 000000000..f99616cf6 --- /dev/null +++ b/docs/pptr-testing-library/intro.md @@ -0,0 +1,81 @@ +--- +id: intro +title: Puppeteer Testing Library +--- + +[`pptr-testing-library`][gh] is a lightweight adapter allowing +`dom-testing-library` to be used with [`puppeteer`][ghpuppeteer]. + +``` +npm install --save-dev puppeteer pptr-testing-library +``` + +- [pptr-testing-library on GitHub][gh] + +## Usage + +```js +const puppeteer = require('puppeteer') +const { getDocument, queries, wait } = require('pptr-testing-library') + +const { getByTestId, getByLabelText } = queries + +const browser = await puppeteer.launch() +const page = await browser.newPage() + +// Grab ElementHandle for document +const $document = await getDocument(page) +// Your favorite query methods are available +const $form = await getByTestId($document, 'my-form') +// returned elements are Puppeteer ElementHandles too! +const $email = await getByLabelText($form, 'Email') +// interact with puppeteer like usual +await $email.type('pptr@example.com') +// waiting works too! +await wait(() => getByText('Loading...')) +``` + +A little too un-puppeteer for you? You can attach all the `dom-testing-library` +methods directly onto puppeteer's `ElementHandle` instead! + +```js +const puppeteer = require('puppeteer') +require('pptr-testing-library/extend') + +const browser = await puppeteer.launch() +const page = await browser.newPage() + +// getDocument is added to prototype of Page +const $document = await page.getDocument() +// query methods are added directly to prototype of ElementHandle +const $form = await $document.getByTestId('my-form') +// destructing works if you explicitly call getQueriesForElement +const { getByLabelText } = $form.getQueriesForElement() +// ... +const $email = await getByLabelText('Email') +``` + +### API + +Unique methods, not part of `dom-testing-library`. + +- `getDocument(page: puppeteer.Page): ElementHandle` - get an ElementHandle for + the document + +### Forwarded methods + +`dom-testing-library` is injected into the page that puppeteer is controlling on +each query, so all results will be async. It's still recommended that you use +puppeteer's built-in methods for interaction rather than `fireEvent`. + +## Known Limitations + +- `waitForElement` method is not exposed. Puppeteer has its own set of wait + utilities that somewhat conflict with the style used in `dom-testing-library`. + See + [the issue on GitHub](https://github.com/patrickhulce/pptr-testing-library/issues/3). +- `fireEvent` method is not exposed, use puppeteer's built-ins instead. +- `expect` assertion extensions are not available. + +[gh]: https://github.com/patrickhulce/pptr-testing-library +[ghpuppeteer]: https://github.com/GoogleChrome/puppeteer diff --git a/website/pages/en/index.js b/website/pages/en/index.js index 7f0cdedaf..22204b939 100755 --- a/website/pages/en/index.js +++ b/website/pages/en/index.js @@ -210,6 +210,11 @@ class Index extends React.Component { title: '[ReasonReact Testing Library](./docs/bs-react-testing-library/intro)', }, + { + image: `${baseUrl}img/puppeteer-275x275.png`, + imageAlign: 'top', + title: '[Puppeteer Testing Library](./pptr)', + }, { image: `${baseUrl}img/construction-128x128.png`, imageAlign: 'top', diff --git a/website/pages/en/pptr.js b/website/pages/en/pptr.js new file mode 100644 index 000000000..df27475da --- /dev/null +++ b/website/pages/en/pptr.js @@ -0,0 +1,159 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require('react') + +const CompLibrary = require('../../core/CompLibrary.js') + +const MarkdownBlock = CompLibrary.MarkdownBlock /* Used to read markdown */ +const Container = CompLibrary.Container +const GridBlock = CompLibrary.GridBlock + +class HomeSplash extends React.Component { + render() { + const { siteConfig, language = '' } = this.props + const { baseUrl, docsUrl } = siteConfig + const docsPart = `${docsUrl ? `${docsUrl}/` : ''}` + const langPart = `${language ? `${language}/` : ''}` + const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}` + + const SplashContainer = props => ( +
+
+
{props.children}
+
+
+ ) + + const Logo = props => ( +
+ Project Logo +
+ ) + + const ProjectTitle = () => ( +
+

Puppeteer Testing Library

+
+

+ Simple and complete Puppeteer DOM testing utilities that encourage + good testing practices +

+
+
+ ) + + const PromoSection = props => ( +
+
+
{props.children}
+
+
+ ) + + const Button = props => ( +
+ + {props.children} + +
+ ) + + return ( + + +
+ + + + +
+
+ ) + } +} + +class Index extends React.Component { + render() { + const { config: siteConfig, language = '' } = this.props + const { baseUrl } = siteConfig + + const Block = props => ( + + + + ) + + const FeatureCallout = () => ( + +
+

+ + The more your tests resemble the way your software is used,
+ the more confidence they can give you. +
+

+ + `npm install --save-dev pptr-testing-library` + +
+
+ ) + + const Features = () => ( + + + {[ + { + content: + 'Tests only break when your app breaks, not implementation details', + image: `${baseUrl}img/wrench-128x128.png`, + imageAlign: 'top', + title: 'Write Maintainable Tests', + }, + { + content: 'Interact with your app the same way as your users', + image: `${baseUrl}img/check-128x128.png`, + imageAlign: 'top', + title: 'Develop with Confidence', + }, + { + content: + 'Built-in selectors use semantic HTML and ARIA roles to help you write inclusive code', + image: `${baseUrl}img/tada-128x128.png`, + imageAlign: 'top', + title: 'Accessible by Default', + }, + ]} + + + ) + + return ( +
+ +
+ + +
+
+ ) + } +} + +module.exports = Index diff --git a/website/static/img/puppeteer-275x275.png b/website/static/img/puppeteer-275x275.png new file mode 100644 index 0000000000000000000000000000000000000000..538a243116618afea2d9bb4b50504939cc99f8b4 GIT binary patch literal 21288 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