-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: playwright init * write some basic tests * test: writing invalid value * improve writeInMonaco function * add gh workflow for playwright * make zod version test a bit smarter * chore: regenerate lock * chore: update vscode settings * feat: provide fixture for reading content within monaco editors * fix: switch to getByRole to have a locator based on accessibility attribs * Update playwright config * Improve fixture management * Fix types * avoid NODEJS types * fix wrong nth for code editor fixtures --------- Co-authored-by: Marco Ilari <marilari88@gmail.com>
- Loading branch information
1 parent
bbc1338
commit 606ef5f
Showing
9 changed files
with
313 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
name: Playwright Tests | ||
on: | ||
push: | ||
branches: [ main, master ] | ||
pull_request: | ||
branches: [ main, master ] | ||
jobs: | ||
test: | ||
timeout-minutes: 60 | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: lts/* | ||
- name: Install dependencies | ||
run: npm ci | ||
- name: Install Playwright Browsers | ||
run: npx playwright install --with-deps | ||
- name: Run Playwright tests | ||
run: npx playwright test | ||
- uses: actions/upload-artifact@v4 | ||
if: always() | ||
with: | ||
name: playwright-report | ||
path: playwright-report/ | ||
retention-days: 30 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,3 +20,7 @@ dist-ssr | |
*.njsproj | ||
*.sln | ||
*.sw? | ||
/test-results/ | ||
/playwright-report/ | ||
/blob-report/ | ||
/playwright/.cache/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
{ | ||
"editor.defaultFormatter": "biomejs.biome" | ||
"editor.defaultFormatter": "biomejs.biome", | ||
"[typescript]": { | ||
"editor.defaultFormatter": "biomejs.biome" | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import {defineConfig, devices} from '@playwright/test' | ||
|
||
/** | ||
* See https://playwright.dev/docs/test-configuration. | ||
*/ | ||
export default defineConfig({ | ||
testDir: './tests', | ||
fullyParallel: true, | ||
forbidOnly: !!process.env.CI, | ||
retries: process.env.CI ? 2 : 0, | ||
workers: process.env.CI ? 1 : undefined, | ||
reporter: 'html', | ||
use: { | ||
baseURL: 'http://localhost:5173/', | ||
trace: 'on-first-retry', | ||
}, | ||
|
||
projects: [ | ||
{ | ||
name: 'chromium', | ||
use: {...devices['Desktop Chrome']}, | ||
}, | ||
|
||
{ | ||
name: 'firefox', | ||
use: {...devices['Desktop Firefox']}, | ||
}, | ||
], | ||
|
||
webServer: { | ||
command: 'npm run dev', | ||
url: 'http://localhost:5173/', | ||
reuseExistingServer: !process.env.CI, | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import type {Locator, Page} from '@playwright/test' | ||
import {test as base} from '@playwright/test' | ||
|
||
export const test = base.extend<{ | ||
codeEditors: CodeEditors | ||
}>({ | ||
codeEditors: async ({page}, use) => { | ||
const codeEditors = new CodeEditors(page) | ||
await use(codeEditors) | ||
}, | ||
page: async ({baseURL, page}, use) => { | ||
if (!baseURL) throw new Error('baseURL is required') | ||
await page.goto(baseURL) | ||
await use(page) | ||
}, | ||
}) | ||
|
||
export class CodeEditors { | ||
private readonly codeEditors: Locator | ||
|
||
constructor(public readonly page: Page) { | ||
this.codeEditors = this.page.getByRole('code') | ||
} | ||
|
||
async getSchemaEditorContent({formatOutput = true}: {formatOutput?: boolean} = {}) { | ||
return await getMonacoContent({locator: this.codeEditors.first(), formatOutput}) | ||
} | ||
|
||
async getValueEditorsContent({ | ||
nth = 0, | ||
formatOutput = true, | ||
}: {nth?: number; formatOutput?: boolean} = {}) { | ||
return await getMonacoContent({locator: this.codeEditors.nth(nth + 1), formatOutput}) | ||
} | ||
|
||
async writeSchema({ | ||
text, | ||
replacePreviousContent = true, | ||
}: {text: string; replacePreviousContent?: boolean}) { | ||
await writeInMonaco({ | ||
locator: this.codeEditors.first(), | ||
page: this.page, | ||
text, | ||
replacePreviousContent, | ||
}) | ||
} | ||
|
||
async writeValue({ | ||
nth = 0, | ||
text, | ||
replacePreviousContent = true, | ||
}: {nth?: number; text: string; replacePreviousContent?: boolean}) { | ||
await writeInMonaco({ | ||
locator: this.codeEditors.nth(nth + 1), | ||
page: this.page, | ||
text, | ||
replacePreviousContent, | ||
}) | ||
} | ||
} | ||
|
||
/** | ||
* This function can be used to write some content within a monaco editor | ||
* | ||
* @param {Object} params - The parameters object | ||
* @param {Locator} params.locator - The locator for the editor element | ||
* @param {Page} params.page - The Playwright page object | ||
* @param {string} params.text - The text to write inside the editor | ||
* @param {boolean} [params.replacePreviousContent=true] - Optionally delete the existing content in the editor. Defaults to true | ||
*/ | ||
const writeInMonaco = async ({ | ||
locator, | ||
page, | ||
text, | ||
replacePreviousContent, | ||
}: { | ||
locator: Locator | ||
page: Page | ||
text: string | ||
replacePreviousContent?: boolean | ||
}) => { | ||
await locator.click() | ||
if (replacePreviousContent) { | ||
await page.keyboard.press('ControlOrMeta+KeyA') | ||
} | ||
await page.keyboard.type(text) | ||
} | ||
|
||
/** | ||
* This function can be used to retrieve the full content within a monaco editor | ||
* | ||
* @param {Object} params - The parameters object | ||
* @param {Locator} params.locator - The locator for the editor element | ||
* @param {Page} params.page - The playwright page object | ||
* @param {boolean} [params.formatOutput=true] - Optionally clean the string to have a more reliable way of asserting equalities. Defaults to true | ||
*/ | ||
export const getMonacoContent = async ({ | ||
locator, | ||
formatOutput = true, | ||
}: {locator: Locator; formatOutput?: boolean}) => { | ||
const value = await locator.textContent() | ||
|
||
if (formatOutput) { | ||
return value?.replace(/\s+/g, '') | ||
} | ||
|
||
return value | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import {expect} from '@playwright/test' | ||
|
||
import * as zod from '../src/zod' | ||
import {test} from './fixtures' | ||
|
||
test('has title "Zod Playground', async ({page}) => { | ||
await expect(page).toHaveTitle(/Zod Playground/) | ||
}) | ||
|
||
test('has header with title, share, theme toggler and github repo link', async ({page}) => { | ||
await expect(page.getByText('Zod Playground')).toBeVisible() | ||
await expect(page.getByRole('button', {name: 'Share'})).toBeVisible() | ||
await expect(page.getByLabel('Toggle color scheme')).toBeVisible() | ||
await expect(page.getByRole('banner').getByRole('link')).toHaveAttribute( | ||
'href', | ||
'https://github.com/marilari88/zod-playground', | ||
) | ||
}) | ||
|
||
test('zod version switch', async ({page}) => { | ||
const latestZodVersion = (await zod.getVersions('latest'))[0] | ||
const anotherZodVersion = (await zod.getVersions()).find( | ||
(zVersion) => zVersion !== latestZodVersion, | ||
) | ||
|
||
await page.getByRole('button', {name: `v${latestZodVersion}`}).click() | ||
await page.getByRole('option', {name: anotherZodVersion}).click() | ||
|
||
await expect(page.getByRole('button', {name: `v${latestZodVersion}`})).not.toBeVisible() | ||
await expect(page.getByRole('button', {name: `v${anotherZodVersion}`})).toBeVisible() | ||
}) | ||
|
||
test('has default schema', async ({codeEditors}) => { | ||
const editorValue = await codeEditors.getSchemaEditorContent() | ||
|
||
expect(editorValue).toEqual('1234z.object({name:z.string(),birth_year:z.number().optional()})') | ||
}) | ||
|
||
test('has invalid marker when an invalid value is in the Value Editor', async ({ | ||
page, | ||
codeEditors, | ||
}) => { | ||
await codeEditors.writeValue({ | ||
text: 'Invalid value', | ||
}) | ||
|
||
await expect(page.locator('div').filter({hasText: /^Invalid$/})).toBeVisible() | ||
}) |