Skip to content

Commit

Permalink
Improve e2e and GitHub Actions caching (#3805)
Browse files Browse the repository at this point in the history
* Update GH Actions

* Fix unit test command

* Fix next-link issue

* Fix start:app

* Fix react

* Fix playwright tests w/react event system changes

* Use .blur() in playwright (h/t chatgpt for messing this up)

* Upgrade @testing-library/react

* Switch to .blur()

* Fix e2e react usage (#3806)

* Fix e2e react usage

* Fix lockfile
  • Loading branch information
jaredpalmer authored May 28, 2023
1 parent c3f34e1 commit 4fcf01c
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 179 deletions.
34 changes: 32 additions & 2 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,47 @@ on:
branches: [main]
jobs:
test:
timeout-minutes: 10
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT

- uses: actions/cache@v3
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn

- name: Get installed Playwright version
id: playwright-version
run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_ENV

- name: Cache playwright binaries
uses: actions/cache@v3
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}

- name: Install Playwright Browsers
run: yarn playwright install --with-deps
if: steps.playwright-cache.outputs.cache-hit != 'true'
- run: yarn playwright install-deps
if: steps.playwright-cache.outputs.cache-hit != 'true'

- name: Run Playwright tests
run: yarn playwright test
- uses: actions/upload-artifact@v3
Expand Down
24 changes: 18 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,29 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'jaredpalmer/formik'
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Use Node.js 16.x
uses: actions/setup-node@v1
- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
version: 16.x
node-version: 18.x

- name: Install deps and build (with cache)
uses: bahmutov/npm-install@v1
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT

- uses: actions/cache@v3
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install Dependencies
run: yarn install

- name: Create Release Pull Request or Publish to npm
uses: changesets/action@master
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 1
- uses: preactjs/compressed-size-action@v2
Expand Down
17 changes: 11 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,27 @@ jobs:

strategy:
matrix:
node: ['16.x']
node: ['18.x']

name: Test on node ${{ matrix.node }}

steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3

- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}

- uses: actions/cache@v1
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT

- uses: actions/cache@v3
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ~/.cache/yarn
key: ${{ runner.os }}-yarn-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }}
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
Expand Down
6 changes: 3 additions & 3 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
},
"dependencies": {
"formik": "latest",
"next": "latest",
"react": "latest",
"react-dom": "latest",
"next": "^12.0.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"yup": "^0.29.3"
},
"devDependencies": {
Expand Down
151 changes: 77 additions & 74 deletions app/pages/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,87 @@ import React from 'react';
import { Formik, Field, Form, ErrorMessage } from 'formik';
import * as Yup from 'yup';

let renderCount = 0;
const Basic = () => {
const renderCount = React.useRef(0);
return (
<div>
<h1>Sign Up</h1>
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
favorite: '',
checked: [],
picked: '',
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.email('Invalid email address')
.required('Required'),
firstName: Yup.string().required('Required'),
lastName: Yup.string()
.min(2, 'Must be longer than 2 characters')
.max(20, 'Nice try, nobody has a last name that long')
.required('Required'),
})}
onSubmit={async values => {
await new Promise(r => setTimeout(r, 500));
alert(JSON.stringify(values, null, 2));
}}
>
<Form>
<Field name="firstName" placeholder="Jane" />
<ErrorMessage name="firstName" component="p" />

const Basic = () => (
<div>
<h1>Sign Up</h1>
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
favorite: '',
checked: [],
picked: '',
}}
validationSchema={Yup.object().shape({
email: Yup.string().email('Invalid email address').required('Required'),
firstName: Yup.string().required('Required'),
lastName: Yup.string()
.min(2, 'Must be longer than 2 characters')
.max(20, 'Nice try, nobody has a last name that long')
.required('Required'),
})}
onSubmit={async values => {
await new Promise(r => setTimeout(r, 500));
alert(JSON.stringify(values, null, 2));
}}
>
<Form>
<Field name="firstName" placeholder="Jane" />
<ErrorMessage name="firstName" component="p" />
<Field name="lastName" placeholder="Doe" />
<ErrorMessage name="lastName" component="p" />

<Field name="lastName" placeholder="Doe" />
<ErrorMessage name="lastName" component="p" />
<Field
id="email"
name="email"
placeholder="jane@acme.com"
type="email"
/>
<ErrorMessage name="email" component="p" />

<Field
id="email"
name="email"
placeholder="jane@acme.com"
type="email"
/>
<ErrorMessage name="email" component="p" />

<label>
<Field type="checkbox" name="toggle" />
<span style={{ marginLeft: 3 }}>Toggle</span>
</label>

<div id="checkbox-group">Checkbox Group </div>
<div role="group" aria-labelledby="checkbox-group">
<label>
<Field type="checkbox" name="checked" value="One" />
One
</label>
<label>
<Field type="checkbox" name="checked" value="Two" />
Two
</label>
<label>
<Field type="checkbox" name="checked" value="Three" />
Three
<Field type="checkbox" name="toggle" />
<span style={{ marginLeft: 3 }}>Toggle</span>
</label>
</div>
<div id="my-radio-group">Picked</div>
<div role="group" aria-labelledby="my-radio-group">
<label>
<Field type="radio" name="picked" value="One" />
One
</label>
<label>
<Field type="radio" name="picked" value="Two" />
Two
</label>
</div>
<button type="submit">Submit</button>
<div id="renderCounter">{renderCount++}</div>
</Form>
</Formik>
</div>
);

<div id="checkbox-group">Checkbox Group </div>
<div role="group" aria-labelledby="checkbox-group">
<label>
<Field type="checkbox" name="checked" value="One" />
One
</label>
<label>
<Field type="checkbox" name="checked" value="Two" />
Two
</label>
<label>
<Field type="checkbox" name="checked" value="Three" />
Three
</label>
</div>
<div id="my-radio-group">Picked</div>
<div role="group" aria-labelledby="my-radio-group">
<label>
<Field type="radio" name="picked" value="One" />
One
</label>
<label>
<Field type="radio" name="picked" value="Two" />
Two
</label>
</div>
<button type="submit">Submit</button>
<div id="renderCounter">{renderCount.current++}</div>
</Form>
</Formik>
</div>
);
};

export default Basic;
8 changes: 2 additions & 6 deletions app/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,10 @@ function Home() {
<h1>Formik Examples and Fixtures</h1>
<ul>
<li>
<Link href="/basic">
<a>Basic</a>
</Link>
<Link href="/basic">Basic</Link>
</li>
<li>
<Link href="/async-submission">
<a>Async Submission</a>
</Link>
<Link href="/async-submission">Async Submission</Link>
</li>
</ul>
<style jsx>{`
Expand Down
34 changes: 16 additions & 18 deletions e2e/basic.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { test, expect } from '@playwright/test';

test('should validate before submit', async ({ page }) => {
await page.goto('http://localhost:3000/basic');
await page.goto('/basic');

// Submit the form
await page.click('button[type=submit]');
Expand All @@ -21,39 +21,37 @@ test('should validate before submit', async ({ page }) => {
});

test('should validate show errors on change and blur', async ({ page }) => {
await page.goto('http://localhost:3000/sign-in');
await page.goto('/sign-in');

await page.fill('input[name="username"]', 'john');
await page.dispatchEvent('input[name="username"]', 'blur');
await page.locator('input[name="username"]').blur();
expect(
await page.$$eval('input[name="username"] + p', nodes => nodes.length)
).toBe(0);
await page.locator('input[name="username"] + p').textContent.length
).toEqual(1);

await page.fill('input[name="password"]', '123');
await page.dispatchEvent('input[name="password"]', 'blur');
await page.locator('input[name="password"]').blur();
expect(
await page.$$eval('input[name="password"] + p', nodes => nodes.length)
).toBe(0);
await page.locator('input[name="password"] + p').textContent.length
).toEqual(1);

expect(await page.textContent('#error-log')).toContain('[]');
});

test('should validate show errors on blur only', async ({ page }) => {
await page.goto(
'http://localhost:3000/sign-in?validateOnMount=false&validateOnChange=false'
);
await page.goto('/sign-in?validateOnMount=false&validateOnChange=false');

await page.fill('input[name="username"]', 'john');
await page.dispatchEvent('input[name="username"]', 'blur');
await page.locator('input[name="username"]').blur();
expect(
await page.$$eval('input[name="username"] + p', nodes => nodes.length)
).toBe(0);
await page.locator('input[name="username"] + p').textContent.length
).toEqual(1);

await page.fill('input[name="password"]', '123');
await page.dispatchEvent('input[name="password"]', 'blur');
await page.locator('input[name="password"]').blur();
expect(
await page.$$eval('input[name="password"] + p', nodes => nodes.length)
).toBe(0);
await page.locator('input[name="password"] + p').textContent.length
).toEqual(1);

expect(await page.textContent('#error-log')).toContain(
JSON.stringify(
Expand All @@ -77,7 +75,7 @@ test('should validate autofill', async ({ page }) => {
await page.dispatchEvent(selector, 'change');
};

await page.goto('http://localhost:3000/sign-in');
await page.goto('/sign-in');

await setInputValue('input[name="username"]', '123');
await setInputValue('input[name="password"]', '123');
Expand Down
Loading

1 comment on commit 4fcf01c

@vercel
Copy link

@vercel vercel bot commented on 4fcf01c May 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

formik-docs – ./website

formik-docs-git-main-formik.vercel.app
formik-docs-formik.vercel.app
www.formik.org
formik-docs.vercel.app
formik.org

Please sign in to comment.