chore: remove create-playwright, it is in monorepo by mistake (#10654)
This commit is contained in:
parent
6e00af3b2e
commit
541248006c
31
.github/workflows/package_create_playwright.yml
vendored
31
.github/workflows/package_create_playwright.yml
vendored
|
|
@ -1,31 +0,0 @@
|
||||||
name: create-playwright CI
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
paths:
|
|
||||||
- 'packages/create-playwright/**/*'
|
|
||||||
- '.github/workflows/package_create_playwright.yml'
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
paths:
|
|
||||||
- 'packages/create-playwright/**/*'
|
|
||||||
- '.github/workflows/package_create_playwright.yml'
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
node-version: [12.x, 14.x, 16.x]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
cache: 'npm'
|
|
||||||
- run: npm i -g npm@8
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm run build
|
|
||||||
- run: npm run test
|
|
||||||
working-directory: packages/create-playwright/
|
|
||||||
33
package-lock.json
generated
33
package-lock.json
generated
|
|
@ -39,7 +39,6 @@
|
||||||
"@types/yazl": "^2.4.2",
|
"@types/yazl": "^2.4.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
"@vercel/ncc": "^0.31.1",
|
|
||||||
"@zip.js/zip.js": "^2.3.17",
|
"@zip.js/zip.js": "^2.3.17",
|
||||||
"ansi-to-html": "^0.7.1",
|
"ansi-to-html": "^0.7.1",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
|
|
@ -1657,15 +1656,6 @@
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vercel/ncc": {
|
|
||||||
"version": "0.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.31.1.tgz",
|
|
||||||
"integrity": "sha512-g0FAxwdViI6UzsiVz5HssIHqjcPa1EHL6h+2dcJD893SoCJaGdqqgUF09xnMW6goWnnhbLvgiKlgJWrJa+7qYA==",
|
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
|
||||||
"ncc": "dist/ncc/cli.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@webassemblyjs/ast": {
|
"node_modules/@webassemblyjs/ast": {
|
||||||
"version": "1.11.1",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
||||||
|
|
@ -2965,10 +2955,6 @@
|
||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/create-playwright": {
|
|
||||||
"resolved": "packages/create-playwright",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/cross-env": {
|
"node_modules/cross-env": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||||
|
|
@ -8950,16 +8936,6 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/create-playwright": {
|
|
||||||
"version": "1.18.0-next",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
|
||||||
"create-playwright": "index.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"packages/playwright": {
|
"packages/playwright": {
|
||||||
"version": "1.18.0-next",
|
"version": "1.18.0-next",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
|
@ -10358,12 +10334,6 @@
|
||||||
"eslint-visitor-keys": "^3.0.0"
|
"eslint-visitor-keys": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@vercel/ncc": {
|
|
||||||
"version": "0.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.31.1.tgz",
|
|
||||||
"integrity": "sha512-g0FAxwdViI6UzsiVz5HssIHqjcPa1EHL6h+2dcJD893SoCJaGdqqgUF09xnMW6goWnnhbLvgiKlgJWrJa+7qYA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@webassemblyjs/ast": {
|
"@webassemblyjs/ast": {
|
||||||
"version": "1.11.1",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
||||||
|
|
@ -11407,9 +11377,6 @@
|
||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"create-playwright": {
|
|
||||||
"version": "file:packages/create-playwright"
|
|
||||||
},
|
|
||||||
"cross-env": {
|
"cross-env": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@
|
||||||
"@types/yazl": "^2.4.2",
|
"@types/yazl": "^2.4.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
"@vercel/ncc": "^0.31.1",
|
|
||||||
"@zip.js/zip.js": "^2.3.17",
|
"@zip.js/zip.js": "^2.3.17",
|
||||||
"ansi-to-html": "^0.7.1",
|
"ansi-to-html": "^0.7.1",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
|
|
|
||||||
4
packages/create-playwright/.gitignore
vendored
4
packages/create-playwright/.gitignore
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
node_modules/
|
|
||||||
yarn-error.log
|
|
||||||
lib/
|
|
||||||
test-results/
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
# This ignores everything by default, except for package.json and LICENSE and README.md.
|
|
||||||
# See https://docs.npmjs.com/misc/developers
|
|
||||||
**/*
|
|
||||||
|
|
||||||
!/lib/**/*
|
|
||||||
!index.js
|
|
||||||
|
|
||||||
!/assets/**/*
|
|
||||||
/assets/.eslintrc.js
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
# Create Playwright
|
|
||||||
|
|
||||||
> Getting started with Playwright with a single command
|
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/create-playwright)
|
|
||||||
[](https://github.com/microsoft/playwright/actions/workflows/package_create_playwright.yml)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm init playwright
|
|
||||||
# Or for Yarn
|
|
||||||
yarn create playwright
|
|
||||||
```
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
// Example files here do not need the copyright notice.
|
|
||||||
module.exports = {
|
|
||||||
'extends': '../../../.eslintrc.js',
|
|
||||||
'rules': {
|
|
||||||
'notice/notice': 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
// @ts-check
|
|
||||||
const { test, expect } = require('@playwright/test');
|
|
||||||
|
|
||||||
test('basic test', async ({ page }) => {
|
|
||||||
await page.goto('https://playwright.dev/');
|
|
||||||
await page.locator('text=Get started').click();
|
|
||||||
await expect(page).toHaveTitle(/Getting started/);
|
|
||||||
});
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
|
|
||||||
test('basic test', async ({ page }) => {
|
|
||||||
await page.goto('https://playwright.dev/');
|
|
||||||
await page.locator('text=Get started').click();
|
|
||||||
await expect(page).toHaveTitle(/Getting started/);
|
|
||||||
});
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inside every test you get a new isolated page instance.
|
|
||||||
* @see https://playwright.dev/docs/intro
|
|
||||||
* @see https://playwright.dev/docs/api/class-page
|
|
||||||
*/
|
|
||||||
test('basic test', async ({ page }) => {
|
|
||||||
await page.goto('https://todomvc.com/examples/vanilla-es6/');
|
|
||||||
|
|
||||||
const inputBox = page.locator('input.new-todo');
|
|
||||||
const todoList = page.locator('.todo-list');
|
|
||||||
|
|
||||||
await inputBox.fill('Learn Playwright');
|
|
||||||
await inputBox.press('Enter');
|
|
||||||
await expect(todoList).toHaveText('Learn Playwright');
|
|
||||||
});
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
await page.goto('https://todomvc.com/examples/vanilla-es6/');
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locators are used to represent a selector on a page and re-use them. They have
|
|
||||||
* strictMode enabled by default. This option will throw an error if the selector
|
|
||||||
* will resolve to multiple elements.
|
|
||||||
* In this example we create a todo item, assert that it exists and then filter
|
|
||||||
* by the completed items to ensure that the item is not visible anymore.
|
|
||||||
* @see https://playwright.dev/docs/api/class-locator
|
|
||||||
*/
|
|
||||||
test('basic interaction', async ({ page }) => {
|
|
||||||
const inputBox = page.locator('input.new-todo');
|
|
||||||
const todoList = page.locator('.todo-list');
|
|
||||||
|
|
||||||
await inputBox.fill('Learn Playwright');
|
|
||||||
await inputBox.press('Enter');
|
|
||||||
await expect(todoList).toHaveText('Learn Playwright');
|
|
||||||
await page.locator('.filters >> text=Completed').click();
|
|
||||||
await expect(todoList).not.toHaveText('Learn Playwright');
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Playwright supports different selector engines which you can combine with '>>'.
|
|
||||||
* @see https://playwright.dev/docs/selectors
|
|
||||||
*/
|
|
||||||
test('element selectors', async ({ page }) => {
|
|
||||||
// When no selector engine is specified, Playwright will use the css selector engine.
|
|
||||||
await page.type('.header input', 'Learn Playwright');
|
|
||||||
// So the selector above is the same as the following:
|
|
||||||
await page.press('css=.header input', 'Enter');
|
|
||||||
|
|
||||||
// select by text with the text selector engine:
|
|
||||||
await page.click('text=All');
|
|
||||||
|
|
||||||
// css allows you to select by attribute:
|
|
||||||
await page.click('[id="toggle-all"]');
|
|
||||||
|
|
||||||
// Combine css and text selectors (https://playwright.dev/docs/selectors/#text-selector)
|
|
||||||
await page.click('.todo-list > li:has-text("Playwright")');
|
|
||||||
await page.click('.todoapp .footer >> text=Completed');
|
|
||||||
|
|
||||||
// Selecting based on layout, with css selector
|
|
||||||
expect(await page.innerText('a:right-of(:text("Active"))')).toBe('Completed');
|
|
||||||
|
|
||||||
// Only visible elements, with css selector
|
|
||||||
await page.click('text=Completed >> visible=true');
|
|
||||||
|
|
||||||
// XPath selector
|
|
||||||
await page.click('xpath=//html/body/section/section/label');
|
|
||||||
});
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
await page.goto('https://todomvc.com/examples/vanilla-es6/');
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All available test assertions are listed here:
|
|
||||||
* @see https://playwright.dev/docs/test-assertions/
|
|
||||||
*/
|
|
||||||
test('should be able to use assertions', async ({ page }) => {
|
|
||||||
await test.step('toHaveTitle/toHaveURL', async () => {
|
|
||||||
await expect(page).toHaveTitle('Vanilla ES6 • TodoMVC');
|
|
||||||
await expect(page).toHaveURL('https://todomvc.com/examples/vanilla-es6/');
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('toBeEmpty/toHaveValue', async () => {
|
|
||||||
const input = page.locator('input.new-todo');
|
|
||||||
await expect(input).toBeEmpty();
|
|
||||||
await input.fill('Buy milk');
|
|
||||||
await expect(input).toHaveValue('Buy milk');
|
|
||||||
await input.press('Enter');
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('toHaveCount/toHaveText/toContainText', async () => {
|
|
||||||
const items = page.locator('.todo-list li');
|
|
||||||
await expect(items).toHaveCount(1);
|
|
||||||
await expect(items.first()).toHaveText('Buy milk');
|
|
||||||
await expect(items).toHaveText(['Buy milk']);
|
|
||||||
await expect(items.first()).toContainText('milk');
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('toBeChecked', async () => {
|
|
||||||
const firstItemCheckbox = page.locator('input[type=checkbox]:left-of(:text("Buy milk"))');
|
|
||||||
await expect(firstItemCheckbox).not.toBeChecked();
|
|
||||||
await firstItemCheckbox.check();
|
|
||||||
await expect(firstItemCheckbox).toBeChecked();
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('toBeVisible/toBeHidden', async () => {
|
|
||||||
await expect(page.locator('text=Buy milk')).toBeVisible();
|
|
||||||
await page.click('text=Active');
|
|
||||||
await expect(page.locator('text=Buy milk')).toBeHidden();
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('toHaveClass/toHaveCSS', async () => {
|
|
||||||
await expect(page.locator('[placeholder="What needs to be done?"]')).toHaveClass('new-todo');
|
|
||||||
await page.click('text=Clear completed');
|
|
||||||
await expect(page.locator('.main')).toHaveCSS('display', 'none');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
|
|
||||||
const fileToUpload = __filename; // '__filename' is the current test file.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this test we wait for an file chooser to appear while we click on an
|
|
||||||
* input. Once the event was emitted we set the file and submit the form.
|
|
||||||
* @see https://playwright.dev/docs/api/class-filechooser
|
|
||||||
*/
|
|
||||||
test('should be able to upload files', async ({ page, context }) => {
|
|
||||||
await page.goto('/file-uploads.html');
|
|
||||||
const [fileChooser] = await Promise.all([
|
|
||||||
page.waitForEvent('filechooser'),
|
|
||||||
page.click('input')
|
|
||||||
]);
|
|
||||||
await fileChooser.setFiles(fileToUpload);
|
|
||||||
await page.click('input[type=submit]');
|
|
||||||
await expect(page.locator('text=4-file-uploads.spec.ts')).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test clicks on an element with the text 'Load user' and waits for a
|
|
||||||
* specific HTTP response. This response contains a JSON body where we assert
|
|
||||||
* some properties.
|
|
||||||
*/
|
|
||||||
test('should be able to read a response body', async ({ page }) => {
|
|
||||||
await page.goto('/network.html');
|
|
||||||
const [response] = await Promise.all([
|
|
||||||
page.waitForResponse('/api/v1/users.json'),
|
|
||||||
page.click('text=Load user')
|
|
||||||
]);
|
|
||||||
await expect(page.locator('#user-full-name')).toContainText('John Doe');
|
|
||||||
const responseBody = await response.json();
|
|
||||||
expect(responseBody.id).toBe(1);
|
|
||||||
expect(responseBody.fullName).toBe('John Doe');
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('mocked responses', () => {
|
|
||||||
/**
|
|
||||||
* Before every test set the request interception handler and fulfill the
|
|
||||||
* requests with a mocked response. See here:
|
|
||||||
* @see https://playwright.dev/docs/network#handle-requests
|
|
||||||
*/
|
|
||||||
test.beforeEach(async ({ context }) => {
|
|
||||||
await context.route('/api/v1/users.json', route => route.fulfill({
|
|
||||||
body: JSON.stringify({
|
|
||||||
'id': 2,
|
|
||||||
'fullName': 'James Bond'
|
|
||||||
}),
|
|
||||||
contentType: 'application/json'
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('be able to mock responses', async ({ page }) => {
|
|
||||||
await page.goto('/network.html');
|
|
||||||
await page.click('text=Load user');
|
|
||||||
await expect(page.locator('p')).toHaveText('User: James Bond');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
# Playwright examples
|
|
||||||
|
|
||||||
This directory contains examples for Playwright. Run them with the following command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run test:e2e-examples
|
|
||||||
yarn test:e2e-examples
|
|
||||||
```
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import { PlaywrightTestConfig } from '@playwright/test';
|
|
||||||
|
|
||||||
// Reference: https://playwright.dev/docs/test-configuration
|
|
||||||
const config: PlaywrightTestConfig = {
|
|
||||||
// Run your local dev server before starting the tests:
|
|
||||||
// https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests
|
|
||||||
webServer: {
|
|
||||||
command: 'node ./server',
|
|
||||||
port: 4345,
|
|
||||||
cwd: __dirname,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
export default config;
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { test as base } from '@playwright/test';
|
|
||||||
import { TodoPage } from './todoPage.pom';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This adds a todoPage fixture which has access to the page instance
|
|
||||||
* @see https://playwright.dev/docs/test-fixtures
|
|
||||||
*/
|
|
||||||
export const test = base.extend<{ todoPage: TodoPage }>({
|
|
||||||
todoPage: async ({ page }, use) => {
|
|
||||||
await use(new TodoPage(page));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expect = test.expect;
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
import { test, expect } from './fixtures';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fixtures are used here to create a TodoApp instance for every test. These are
|
|
||||||
* defined inside the 'fixtures.ts' file. This will reduce the amount of
|
|
||||||
* boilerplate created for each test and makes it more reusable.
|
|
||||||
* @see https://playwright.dev/docs/test-fixtures
|
|
||||||
*/
|
|
||||||
test.beforeEach(async ({ todoPage }) => {
|
|
||||||
await todoPage.goto();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should display zero initial items', async ({ todoPage }) => {
|
|
||||||
await expect(todoPage.listItems).toHaveCount(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to add new items', async ({ todoPage }) => {
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await todoPage.addItem('Example #2');
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1', 'Example #2']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to mark items as completed', async ({ todoPage }) => {
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
const firstListItem = todoPage.listItems.first();
|
|
||||||
await expect(firstListItem).not.toHaveClass('completed');
|
|
||||||
await firstListItem.locator('.toggle').check();
|
|
||||||
await expect(firstListItem).toHaveClass('completed');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should still show the items after a page reload', async ({ page, todoPage }) => {
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1']);
|
|
||||||
await page.reload();
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to filter by uncompleted items', async ({ todoPage }) => {
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await todoPage.addItem('Example #2');
|
|
||||||
await todoPage.addItem('Example #3');
|
|
||||||
await todoPage.listItems.last().locator('.toggle').check();
|
|
||||||
await todoPage.filterByActiveItemsButton.click();
|
|
||||||
await expect(todoPage.listItems).toHaveCount(2);
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1', 'Example #2']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to filter by completed items', async ({ todoPage }) => {
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await todoPage.addItem('Example #2');
|
|
||||||
await todoPage.addItem('Example #3');
|
|
||||||
await todoPage.listItems.last().locator('.toggle').check();
|
|
||||||
await todoPage.filterByCompletedItemsButton.click();
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #3']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to delete completed items', async ({ todoPage }) => {
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await todoPage.listItems.last().locator('.toggle').check();
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1']);
|
|
||||||
await todoPage.listItems.first().locator('button.destroy').click();
|
|
||||||
await expect(todoPage.listItems).toHaveText([]);
|
|
||||||
});
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
import { TodoPage } from './todoPage.pom';
|
|
||||||
|
|
||||||
test.describe('ToDo App', () => {
|
|
||||||
test('should display zero initial items', async ({ page }) => {
|
|
||||||
const todoPage = new TodoPage(page);
|
|
||||||
await todoPage.goto();
|
|
||||||
await expect(todoPage.listItems).toHaveCount(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to add new items', async ({ page }) => {
|
|
||||||
const todoPage = new TodoPage(page);
|
|
||||||
await todoPage.goto();
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await todoPage.addItem('Example #2');
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1', 'Example #2']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to mark items as completed', async ({ page }) => {
|
|
||||||
const todoPage = new TodoPage(page);
|
|
||||||
await todoPage.goto();
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
const firstListItem = todoPage.listItems.first();
|
|
||||||
await expect(firstListItem).not.toHaveClass('completed');
|
|
||||||
await firstListItem.locator('.toggle').check();
|
|
||||||
await expect(firstListItem).toHaveClass('completed');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should still show the items after a page reload', async ({ page }) => {
|
|
||||||
const todoPage = new TodoPage(page);
|
|
||||||
await todoPage.goto();
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1']);
|
|
||||||
await page.reload();
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to filter by uncompleted items', async ({ page }) => {
|
|
||||||
const todoPage = new TodoPage(page);
|
|
||||||
await todoPage.goto();
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await todoPage.addItem('Example #2');
|
|
||||||
await todoPage.addItem('Example #3');
|
|
||||||
await todoPage.listItems.last().locator('.toggle').check();
|
|
||||||
await todoPage.filterByActiveItemsButton.click();
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1', 'Example #2']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to filter by completed items', async ({ page }) => {
|
|
||||||
const todoPage = new TodoPage(page);
|
|
||||||
await todoPage.goto();
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await todoPage.addItem('Example #2');
|
|
||||||
await todoPage.addItem('Example #3');
|
|
||||||
await todoPage.listItems.last().locator('.toggle').check();
|
|
||||||
await todoPage.filterByCompletedItemsButton.click();
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #3']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to delete completed items', async ({ page }) => {
|
|
||||||
const todoPage = new TodoPage(page);
|
|
||||||
await todoPage.goto();
|
|
||||||
await todoPage.addItem('Example #1');
|
|
||||||
await todoPage.listItems.last().locator('.toggle').check();
|
|
||||||
await expect(todoPage.listItems).toHaveText(['Example #1']);
|
|
||||||
await todoPage.listItems.first().locator('button.destroy').click();
|
|
||||||
await expect(todoPage.listItems).toHaveText([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
import { Page } from '@playwright/test';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a Page Object Model (POM) class for the application's Todo page. It
|
|
||||||
* provides locators and common operations that make writing tests easier.
|
|
||||||
* @see https://playwright.dev/docs/test-pom
|
|
||||||
*/
|
|
||||||
export class TodoPage {
|
|
||||||
/**
|
|
||||||
* Locators are used to reflect a element on the page with a selector.
|
|
||||||
* @see https://playwright.dev/docs/api/class-locator
|
|
||||||
*/
|
|
||||||
listItems = this.page.locator('.todo-list li');
|
|
||||||
inputBox = this.page.locator('input.new-todo');
|
|
||||||
filterByActiveItemsButton = this.page.locator('.filters >> text=Active');
|
|
||||||
filterByCompletedItemsButton = this.page.locator('.filters >> text=Completed');
|
|
||||||
|
|
||||||
constructor(public readonly page: Page) { }
|
|
||||||
|
|
||||||
async addItem(text: string) {
|
|
||||||
await this.inputBox.fill(text);
|
|
||||||
await this.inputBox.press('Enter');
|
|
||||||
}
|
|
||||||
|
|
||||||
async goto() {
|
|
||||||
await this.page.goto('https://todomvc.com/examples/vanilla-es6/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"fullName": "John Doe"
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
<iframe src="header.html" style="width: 100%; height: 200px; border: 0;"></iframe>
|
|
||||||
|
|
||||||
<form action="/api/v1/file-upload" method="POST" encType="multipart/form-data">
|
|
||||||
<input type="file" name="my-file"/>
|
|
||||||
<input type="submit"/>
|
|
||||||
</form>
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<style>
|
|
||||||
p, h1 {
|
|
||||||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>
|
|
||||||
Playwright 🎭 Examples
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Run them by executing:
|
|
||||||
</p>
|
|
||||||
<pre>
|
|
||||||
# NPM
|
|
||||||
npm run test:e2e-examples
|
|
||||||
# Yarn
|
|
||||||
yarn test:e2e-examples
|
|
||||||
</pre>
|
|
||||||
</body>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
<iframe src="header.html" style="width: 100%; height: 200px; border: 0;"></iframe>
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
<iframe src="header.html" style="width: 100%; height: 200px; border: 0;"></iframe>
|
|
||||||
|
|
||||||
<button>Load user</button>
|
|
||||||
<p>
|
|
||||||
User:
|
|
||||||
<span id="user-full-name"></span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.querySelector("button").addEventListener("click", () => {
|
|
||||||
fetch("/api/v1/users.json")
|
|
||||||
.then(resp => resp.json())
|
|
||||||
.then(user => {
|
|
||||||
document.querySelector("#user-full-name").innerText = user.fullName
|
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
// @ts-check
|
|
||||||
const path = require('path');
|
|
||||||
const http = require('http');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const port = 4345;
|
|
||||||
|
|
||||||
class Server {
|
|
||||||
constructor() {
|
|
||||||
this._server = http.createServer(this._handle.bind(this));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {import('http').IncomingMessage} req
|
|
||||||
* @param {import('http').ServerResponse} res
|
|
||||||
*/
|
|
||||||
_handle(req, res) {
|
|
||||||
switch (req.url) {
|
|
||||||
case '/api/v1/file-upload':
|
|
||||||
const chunks = [];
|
|
||||||
req.on('data', chunk => chunks.push(chunk));
|
|
||||||
req.on('end', () => {
|
|
||||||
const lines = Buffer.concat(chunks).toString().split('\n');
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
if (lines[i].trim() === '') {
|
|
||||||
res.end(lines.slice(0, i - 1).join('\n'))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
const localFilePath = path.join(__dirname, 'assets', req.url === '/' ? 'index.html' : req.url);
|
|
||||||
function shouldServe() {
|
|
||||||
try {
|
|
||||||
const result = fs.statSync(localFilePath)
|
|
||||||
if (result.isDirectory())
|
|
||||||
return false;
|
|
||||||
return true
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!shouldServe()) {
|
|
||||||
res.writeHead(404);
|
|
||||||
res.end('Not found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const extension2ContentType = {
|
|
||||||
'.html': 'text/html',
|
|
||||||
'.json': 'application/json',
|
|
||||||
}
|
|
||||||
const contentType = extension2ContentType[path.extname(localFilePath)];
|
|
||||||
if (contentType)
|
|
||||||
res.setHeader('Content-Type', contentType);
|
|
||||||
const content = fs.readFileSync(localFilePath);
|
|
||||||
res.end(content);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param {number} port
|
|
||||||
*/
|
|
||||||
async listen(port) {
|
|
||||||
await new Promise(resolve => this._server.listen(port, () => resolve));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
console.log(`Listening on http://127.0.0.1:${port}`);
|
|
||||||
await new Server().listen(port);
|
|
||||||
})()
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
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@v2
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14.x'
|
|
||||||
- name: Install dependencies
|
|
||||||
run: {{installDepsCommand}}
|
|
||||||
- name: Install Playwright
|
|
||||||
run: npx playwright install --with-deps
|
|
||||||
- name: Run Playwright tests
|
|
||||||
run: {{runTestsCommand}}
|
|
||||||
- uses: actions/upload-artifact@v2
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: playwright-test-results
|
|
||||||
path: test-results/
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
// @ts-check
|
|
||||||
const { devices } = require('@playwright/test');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see https://playwright.dev/docs/test-configuration
|
|
||||||
* @type {import('@playwright/test').PlaywrightTestConfig}
|
|
||||||
*/
|
|
||||||
const config = {
|
|
||||||
testDir: path.join(__dirname, '{{testDir}}'), /* Test directory */
|
|
||||||
forbidOnly: !!process.env.CI, /* Whether to exit with an error if any tests or groups are marked as test.only() or test.describe.only(). Useful on CI. */
|
|
||||||
retries: process.env.CI ? 2 : 0, /* If a test fails on CI, retry it additional 2 times */
|
|
||||||
// timeout: 30 * 1000, /* Timeout per test */
|
|
||||||
// outputDir: 'test-results/', /* Artifacts folder where screenshots, videos, and traces are stored. */
|
|
||||||
|
|
||||||
// webServer: { /* Run your local dev server before starting the tests: */
|
|
||||||
// command: 'npm run start', /* https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests */
|
|
||||||
// port: 3000,
|
|
||||||
// },
|
|
||||||
|
|
||||||
use: {
|
|
||||||
trace: 'on-first-retry', /* Retry a test if its failing with enabled tracing. This allows you to analyse the DOM, console logs, network traffic etc. */
|
|
||||||
// contextOptions: { /* All available context options: https://playwright.dev/docs/api/class-browser#browser-new-context */
|
|
||||||
// ignoreHTTPSErrors: true,
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: 'chromium',
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Chrome'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'firefox',
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Firefox'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'webkit',
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Safari'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/* Test against mobile viewports. */
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Chrome',
|
|
||||||
// use: {
|
|
||||||
// ...devices['Pixel 5'],
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Safari',
|
|
||||||
// use: {
|
|
||||||
// ...devices['iPhone 12'],
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
/* Test against stable browsers. */
|
|
||||||
// {
|
|
||||||
// name: 'Microsoft Edge',
|
|
||||||
// use: {
|
|
||||||
// channel: 'msedge',
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Google Chrome',
|
|
||||||
// use: {
|
|
||||||
// channel: 'chrome',
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
module.exports = config;
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
import { PlaywrightTestConfig, devices } from '@playwright/test';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
// Reference: https://playwright.dev/docs/test-configuration
|
|
||||||
const config: PlaywrightTestConfig = {
|
|
||||||
testDir: path.join(__dirname, '{{testDir}}'), /* Test directory */
|
|
||||||
forbidOnly: !!process.env.CI, /* Whether to exit with an error if any tests or groups are marked as test.only() or test.describe.only(). Useful on CI. */
|
|
||||||
retries: process.env.CI ? 2 : 0, /* If a test fails on CI, retry it additional 2 times */
|
|
||||||
// timeout: 30 * 1000, /* Timeout per test */
|
|
||||||
// outputDir: 'test-results/', /* Artifacts folder where screenshots, videos, and traces are stored. */
|
|
||||||
|
|
||||||
// webServer: { /* Run your local dev server before starting the tests: */
|
|
||||||
// command: 'npm run start', /* https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests */
|
|
||||||
// port: 3000,
|
|
||||||
// },
|
|
||||||
|
|
||||||
use: {
|
|
||||||
trace: 'on-first-retry', /* Retry a test if its failing with enabled tracing (analyse the DOM, console logs, network traffic): https://playwright.dev/docs/trace-viewer */
|
|
||||||
// contextOptions: { /* All available context options: https://playwright.dev/docs/api/class-browser#browser-new-context */
|
|
||||||
// ignoreHTTPSErrors: true,
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: 'chromium',
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Chrome'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'firefox',
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Firefox'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'webkit',
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Safari'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/* Test against mobile viewports. */
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Chrome',
|
|
||||||
// use: {
|
|
||||||
// ...devices['Pixel 5'],
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Safari',
|
|
||||||
// use: {
|
|
||||||
// ...devices['iPhone 12'],
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
/* Test against stable browsers. */
|
|
||||||
// {
|
|
||||||
// name: 'Microsoft Edge',
|
|
||||||
// use: {
|
|
||||||
// channel: 'msedge',
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Google Chrome',
|
|
||||||
// use: {
|
|
||||||
// channel: 'chrome',
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
export default config;
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
require('./lib/index')
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"name": "create-playwright",
|
|
||||||
"version": "1.18.0-next",
|
|
||||||
"description": "Getting started with writing end-to-end tests with Playwright.",
|
|
||||||
"repository": "github:Microsoft/playwright",
|
|
||||||
"homepage": "https://playwright.dev",
|
|
||||||
"author": {
|
|
||||||
"name": "Microsoft Corporation"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"main": "index.js",
|
|
||||||
"bin": {
|
|
||||||
"create-playwright": "./index.js"
|
|
||||||
},
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"scripts": {
|
|
||||||
"test": "npx playwright test"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
import { PlaywrightTestConfig } from '@playwright/test';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
const config: PlaywrightTestConfig = {
|
|
||||||
timeout: 120 * 1000,
|
|
||||||
testDir: path.join(__dirname, 'tests'),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default config;
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import path from 'path';
|
|
||||||
import { Generator } from './generator';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const rootDir = path.resolve(process.cwd(), process.argv[2] || '');
|
|
||||||
const generator = new Generator(rootDir);
|
|
||||||
await generator.run();
|
|
||||||
})().catch(error => {
|
|
||||||
console.error(error);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
|
|
@ -1,222 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
import { prompt } from 'enquirer';
|
|
||||||
import colors from 'ansi-colors';
|
|
||||||
|
|
||||||
import { executeCommands, createFiles, determinePackageManager, executeTemplate, Command, languagetoFileExtension, readDirRecursively } from './utils';
|
|
||||||
|
|
||||||
export type PromptOptions = {
|
|
||||||
testDir: string,
|
|
||||||
installGitHubActions: boolean,
|
|
||||||
language: 'JavaScript' | 'TypeScript'
|
|
||||||
addExamples: boolean,
|
|
||||||
installPlaywrightDependencies: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
const assetsDir = path.join(__dirname, '..', 'assets');
|
|
||||||
const PACKAGE_JSON_TEST_SCRIPT_CMD = 'test:e2e';
|
|
||||||
|
|
||||||
export class Generator {
|
|
||||||
packageManager: 'npm' | 'yarn';
|
|
||||||
constructor(private readonly rootDir: string) {
|
|
||||||
if (!fs.existsSync(rootDir))
|
|
||||||
fs.mkdirSync(rootDir);
|
|
||||||
this.packageManager = determinePackageManager(this.rootDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
async run() {
|
|
||||||
this._printIntro();
|
|
||||||
const answers = await this._askQuestions();
|
|
||||||
const { files, commands } = await this._identifyChanges(answers);
|
|
||||||
executeCommands(this.rootDir, commands);
|
|
||||||
await createFiles(this.rootDir, files);
|
|
||||||
this._patchGitIgnore();
|
|
||||||
await this._patchPackageJSON(answers);
|
|
||||||
this._printOutro(answers);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _printIntro() {
|
|
||||||
console.log(colors.yellow(`Getting started with writing ${colors.bold('end-to-end')} tests with ${colors.bold('Playwright')}:`));
|
|
||||||
console.log(`Initializing project in '${path.relative(process.cwd(), this.rootDir) || '.'}'`);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _askQuestions() {
|
|
||||||
if (process.env.TEST_OPTIONS)
|
|
||||||
return JSON.parse(process.env.TEST_OPTIONS);
|
|
||||||
return await prompt<PromptOptions>([
|
|
||||||
{
|
|
||||||
type: 'select',
|
|
||||||
name: 'language',
|
|
||||||
message: 'Do you want to use TypeScript or JavaScript?',
|
|
||||||
choices: [
|
|
||||||
{ name: 'TypeScript' },
|
|
||||||
{ name: 'JavaScript' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
name: 'testDir',
|
|
||||||
message: 'Where to put your end-to-end tests?',
|
|
||||||
initial: fs.existsSync(path.join(this.rootDir, 'tests')) ? 'e2e' : 'tests',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'installGitHubActions',
|
|
||||||
message: 'Add a GitHub Actions workflow?',
|
|
||||||
initial: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'addExamples',
|
|
||||||
message: 'Add common examples which demonstrate Playwright\'s capabilities?',
|
|
||||||
initial: true,
|
|
||||||
},
|
|
||||||
// Avoid installing dependencies on Windows (vast majority does not run create-playwright on Windows)
|
|
||||||
// Avoid installing dependencies on Mac (there are no dependencies)
|
|
||||||
...(process.platform === 'linux' ? [{
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'installPlaywrightDependencies',
|
|
||||||
message: 'Install Playwright operating system dependencies (requires sudo / root - can be done manually via \sudo npx playwright install-deps\')?',
|
|
||||||
initial: true,
|
|
||||||
}] : []),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _identifyChanges(answers: PromptOptions) {
|
|
||||||
const commands: Command[] = [];
|
|
||||||
const files = new Map<string, string>();
|
|
||||||
const fileExtension = languagetoFileExtension(answers.language);
|
|
||||||
|
|
||||||
files.set(`playwright.config.${fileExtension}`, executeTemplate(this._readAsset(`playwright.config.${fileExtension}`), {
|
|
||||||
testDir: answers.testDir,
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (answers.installGitHubActions) {
|
|
||||||
const githubActionsScript = executeTemplate(this._readAsset('github-actions.yml'), {
|
|
||||||
installDepsCommand: this.packageManager === 'npm' ? 'npm ci' : 'yarn',
|
|
||||||
runTestsCommand: commandToRunTests(this.packageManager),
|
|
||||||
});
|
|
||||||
files.set('.github/workflows/playwright.yml', githubActionsScript);
|
|
||||||
}
|
|
||||||
|
|
||||||
files.set(path.join(answers.testDir, `example.spec.${fileExtension}`), this._readAsset(`example.spec.${fileExtension}`));
|
|
||||||
|
|
||||||
if (answers.addExamples)
|
|
||||||
await this._collectExamples(answers, files);
|
|
||||||
|
|
||||||
if (!fs.existsSync(path.join(this.rootDir, 'package.json'))) {
|
|
||||||
commands.push({
|
|
||||||
name: `Initializing ${this.packageManager === 'yarn' ? 'Yarn' : 'NPM'} project`,
|
|
||||||
command: this.packageManager === 'yarn' ? 'yarn init -y' : 'npm init -y',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
commands.push({
|
|
||||||
name: 'Installing Playwright Test',
|
|
||||||
command: this.packageManager === 'yarn' ? 'yarn add --dev @playwright/test' : 'npm install --save-dev @playwright/test',
|
|
||||||
});
|
|
||||||
|
|
||||||
commands.push({
|
|
||||||
name: 'Downloading browsers',
|
|
||||||
command: 'npx playwright install' + (answers.installPlaywrightDependencies ? ' --with-deps' : ''),
|
|
||||||
});
|
|
||||||
|
|
||||||
return { files, commands };
|
|
||||||
}
|
|
||||||
|
|
||||||
private _patchGitIgnore() {
|
|
||||||
const gitIgnorePath = path.join(this.rootDir, '.gitignore');
|
|
||||||
let gitIgnore = '';
|
|
||||||
if (fs.existsSync(gitIgnorePath))
|
|
||||||
gitIgnore = fs.readFileSync(gitIgnorePath, 'utf-8').trimEnd() + '\n';
|
|
||||||
if (!gitIgnore.includes('node_modules'))
|
|
||||||
gitIgnore += 'node_modules/\n';
|
|
||||||
gitIgnore += 'test-results/\n';
|
|
||||||
gitIgnore += 'playwright-report/\n';
|
|
||||||
fs.writeFileSync(gitIgnorePath, gitIgnore);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _readAsset(asset: string): string {
|
|
||||||
return fs.readFileSync(path.isAbsolute(asset) ? asset : path.join(assetsDir, asset), 'utf-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _collectExamples(answers: PromptOptions, files: Map<string, string>) {
|
|
||||||
const outDir = answers.testDir + '-examples';
|
|
||||||
const examplesDir = path.join(assetsDir, 'examples');
|
|
||||||
|
|
||||||
for (const example of await readDirRecursively(examplesDir)) {
|
|
||||||
const relativePath = path.relative(examplesDir, example);
|
|
||||||
files.set(path.join(outDir, relativePath), this._readAsset(example));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _patchPackageJSON(answers: PromptOptions) {
|
|
||||||
const packageJSON = JSON.parse(fs.readFileSync(path.join(this.rootDir, 'package.json'), 'utf-8'));
|
|
||||||
if (!packageJSON.scripts)
|
|
||||||
packageJSON.scripts = {};
|
|
||||||
if (packageJSON.scripts['test']?.includes('no test specified'))
|
|
||||||
delete packageJSON.scripts['test'];
|
|
||||||
if (answers.addExamples)
|
|
||||||
packageJSON.scripts['test:e2e-examples'] = `playwright test --config ${path.join(answers.testDir + '-examples', 'playwright.config.ts')}`;
|
|
||||||
packageJSON.scripts[PACKAGE_JSON_TEST_SCRIPT_CMD] = `playwright test`;
|
|
||||||
|
|
||||||
const files = new Map<string, string>();
|
|
||||||
files.set('package.json', JSON.stringify(packageJSON, null, 2) + '\n'); // NPM keeps a trailing new-line
|
|
||||||
await createFiles(this.rootDir, files, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _printOutro(answers: PromptOptions) {
|
|
||||||
console.log(colors.green('✔ Success!') + ' ' + colors.bold(`Created a Playwright Test project at ${this.rootDir}`));
|
|
||||||
const pathToNavigate = path.relative(process.cwd(), this.rootDir);
|
|
||||||
const prefix = pathToNavigate !== '' ? ` cd ${pathToNavigate}\n` : '';
|
|
||||||
const exampleSpecPath = `${answers.testDir}${path.sep}example.spec.${languagetoFileExtension(answers.language)}`;
|
|
||||||
console.log(`Inside that directory, you can run several commands:
|
|
||||||
|
|
||||||
${colors.cyan(commandToRunTests(this.packageManager))}
|
|
||||||
Runs the end-to-end tests.
|
|
||||||
|
|
||||||
${colors.cyan(commandToRunTests(this.packageManager, '--project="Desktop Chrome"'))}
|
|
||||||
Runs the tests only on Desktop Chrome.
|
|
||||||
|
|
||||||
${colors.cyan(commandToRunTests(this.packageManager, exampleSpecPath))}
|
|
||||||
Runs the tests of a specific file.
|
|
||||||
|
|
||||||
${colors.cyan(`${commandToRunTests(this.packageManager, '--debug')}`)}
|
|
||||||
Runs the tests in debug mode.
|
|
||||||
|
|
||||||
We suggest that you begin by typing:
|
|
||||||
|
|
||||||
${colors.cyan(prefix + ' ' + commandToRunTests(this.packageManager))}
|
|
||||||
|
|
||||||
And check out the following files:
|
|
||||||
- ./${pathToNavigate ? pathToNavigate + '/' : ''}${exampleSpecPath} - Example end-to-end test
|
|
||||||
- ./${pathToNavigate ? pathToNavigate + '/' : ''}playwright.config.${languagetoFileExtension(answers.language)} - Playwright Test configuration
|
|
||||||
|
|
||||||
Visit https://playwright.dev/docs/intro for more information. ✨
|
|
||||||
|
|
||||||
Happy hacking! 🎭`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function commandToRunTests(packageManager: 'npm' | 'yarn', args?: string) {
|
|
||||||
if (packageManager === 'yarn')
|
|
||||||
return `yarn ${PACKAGE_JSON_TEST_SCRIPT_CMD}${args ? (' ' + args) : ''}`;
|
|
||||||
return `npm run ${PACKAGE_JSON_TEST_SCRIPT_CMD}${args ? (' -- ' + args) : ''}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "../tsconfig.json"
|
|
||||||
}
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import fs from 'fs';
|
|
||||||
import { execSync } from 'child_process';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import { prompt } from 'enquirer';
|
|
||||||
import colors from 'ansi-colors';
|
|
||||||
|
|
||||||
export type Command = {
|
|
||||||
command: string;
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function executeCommands(cwd: string, commands: Command[]) {
|
|
||||||
for (const { command, name } of commands) {
|
|
||||||
console.log(`${name} (${command})…`);
|
|
||||||
execSync(command, {
|
|
||||||
stdio: 'inherit',
|
|
||||||
cwd,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createFiles(rootDir: string, files: Map<string, string>, force: boolean = false) {
|
|
||||||
for (const [relativeFilePath, value] of files) {
|
|
||||||
const absoluteFilePath = path.join(rootDir, relativeFilePath);
|
|
||||||
if (fs.existsSync(absoluteFilePath) && !force) {
|
|
||||||
const { override } = await prompt<{ override: boolean }>({
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'override',
|
|
||||||
message: `${absoluteFilePath} already exists. Override it?`,
|
|
||||||
initial: false
|
|
||||||
});
|
|
||||||
if (!override)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
console.log(colors.gray(`Writing ${path.relative(process.cwd(), absoluteFilePath)}.`));
|
|
||||||
fs.mkdirSync(path.dirname(absoluteFilePath), { recursive: true });
|
|
||||||
fs.writeFileSync(absoluteFilePath, value, 'utf-8');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function determinePackageManager(rootDir: string): 'yarn' | 'npm' {
|
|
||||||
if (fs.existsSync(path.join(rootDir, 'yarn.lock')))
|
|
||||||
return 'yarn';
|
|
||||||
if (process.env.npm_config_user_agent)
|
|
||||||
return process.env.npm_config_user_agent.includes('yarn') ? 'yarn' : 'npm';
|
|
||||||
return 'npm';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function executeTemplate(input: string, args: Record<string, string>): string {
|
|
||||||
for (const key in args)
|
|
||||||
input = input.replace(`{{${key}}}`, args[key]);
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function languagetoFileExtension(language: 'JavaScript' | 'TypeScript'): 'js' | 'ts' {
|
|
||||||
return language === 'JavaScript' ? 'js' : 'ts';
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function readDirRecursively(dir: string): Promise<string[]> {
|
|
||||||
const dirents = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
||||||
const files = await Promise.all(dirents.map(async (dirent): Promise<string[]|string> => {
|
|
||||||
const res = path.join(dir, dirent.name);
|
|
||||||
return dirent.isDirectory() ? await readDirRecursively(res) : res;
|
|
||||||
}));
|
|
||||||
return files.flat();
|
|
||||||
}
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { test as base } from '@playwright/test';
|
|
||||||
import { spawn, SpawnOptionsWithoutStdio } from 'child_process';
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { PromptOptions } from '../src/generator';
|
|
||||||
|
|
||||||
type TestFixtures = {
|
|
||||||
packageManager: 'npm' | 'yarn';
|
|
||||||
run: (parameters: string[], options: PromptOptions) => Promise<RunResult>,
|
|
||||||
};
|
|
||||||
|
|
||||||
type RunResult = {
|
|
||||||
exitCode: number | null,
|
|
||||||
dir: string,
|
|
||||||
stdout: string,
|
|
||||||
exec: typeof spawnAsync
|
|
||||||
};
|
|
||||||
|
|
||||||
function spawnAsync(cmd: string, args: string[], options?: SpawnOptionsWithoutStdio): Promise<{stdout: string, stderr: string, code: number | null, error?: Error}> {
|
|
||||||
const p = spawn(cmd, args, options);
|
|
||||||
|
|
||||||
return new Promise(resolve => {
|
|
||||||
let stdout = '';
|
|
||||||
let stderr = '';
|
|
||||||
if (process.env.CR_PW_DEBUG) {
|
|
||||||
p.stdout.on('data', chunk => process.stdout.write(chunk));
|
|
||||||
p.stderr.on('data', chunk => process.stderr.write(chunk));
|
|
||||||
}
|
|
||||||
if (p.stdout)
|
|
||||||
p.stdout.on('data', data => stdout += data);
|
|
||||||
if (p.stderr)
|
|
||||||
p.stderr.on('data', data => stderr += data);
|
|
||||||
p.on('close', code => resolve({ stdout, stderr, code }));
|
|
||||||
p.on('error', error => resolve({ stdout, stderr, code: 0, error }));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const test = base.extend<TestFixtures>({
|
|
||||||
packageManager: 'npm',
|
|
||||||
run: async ({ packageManager }, use, testInfo) => {
|
|
||||||
await use(async (parameters: string[], options: PromptOptions): Promise<RunResult> => {
|
|
||||||
fs.mkdirSync(testInfo.outputDir, { recursive: true });
|
|
||||||
const env = packageManager === 'yarn' ? {
|
|
||||||
'npm_config_user_agent': 'yarn'
|
|
||||||
} : undefined;
|
|
||||||
const result = await spawnAsync('node', [path.join(__dirname, '..'), ...parameters], {
|
|
||||||
shell: true,
|
|
||||||
cwd: testInfo.outputDir,
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
...env,
|
|
||||||
'TEST_OPTIONS': JSON.stringify(options),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const execWrapper = (cmd: string, args: string[], options?: SpawnOptionsWithoutStdio): ReturnType<typeof spawnAsync> => {
|
|
||||||
return spawnAsync(cmd, args, {
|
|
||||||
...options,
|
|
||||||
cwd: testInfo.outputDir,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
exitCode: result.code,
|
|
||||||
dir: testInfo.outputDir,
|
|
||||||
stdout: result.stdout,
|
|
||||||
exec: execWrapper,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const expect = test.expect;
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
import { test, expect } from './baseFixtures';
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
for (const packageManager of ['npm', 'yarn'] as ('npm' | 'yarn')[]) {
|
|
||||||
test.describe(`Package manager: ${packageManager}`, () => {
|
|
||||||
test.use({ packageManager });
|
|
||||||
|
|
||||||
test('should generate a project in the current directory', async ({ run }) => {
|
|
||||||
const { exitCode, dir, stdout } = await run([], { installGitHubActions: true, testDir: 'tests', language: 'TypeScript', addExamples: false, installPlaywrightDependencies: true });
|
|
||||||
expect(exitCode).toBe(0);
|
|
||||||
expect(fs.existsSync(path.join(dir, 'tests/example.spec.ts'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'package.json'))).toBeTruthy();
|
|
||||||
if (packageManager === 'npm')
|
|
||||||
expect(fs.existsSync(path.join(dir, 'package-lock.json'))).toBeTruthy();
|
|
||||||
else
|
|
||||||
expect(fs.existsSync(path.join(dir, 'yarn.lock'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'playwright.config.ts'))).toBeTruthy();
|
|
||||||
const playwrightConfigContent = fs.readFileSync(path.join(dir, 'playwright.config.ts'), 'utf8');
|
|
||||||
expect(playwrightConfigContent).toContain('tests');
|
|
||||||
expect(fs.existsSync(path.join(dir, '.github/workflows/playwright.yml'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, '.gitignore'))).toBeTruthy();
|
|
||||||
if (packageManager === 'npm') {
|
|
||||||
expect(stdout).toContain('Initializing NPM project (npm init -y)…');
|
|
||||||
expect(stdout).toContain('Installing Playwright Test (npm install --save-dev @playwright/test)…');
|
|
||||||
} else {
|
|
||||||
expect(stdout).toContain('Initializing Yarn project (yarn init -y)…');
|
|
||||||
expect(stdout).toContain('Installing Playwright Test (yarn add --dev @playwright/test)…');
|
|
||||||
}
|
|
||||||
expect(stdout).toContain('npx playwright install' + process.platform === 'linux' ? ' --with-deps' : '');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should generate a project in a given directory', async ({ run }) => {
|
|
||||||
const { exitCode, dir } = await run(['foobar'], { installGitHubActions: true, testDir: 'tests', language: 'TypeScript', addExamples: false, installPlaywrightDependencies: true });
|
|
||||||
expect(exitCode).toBe(0);
|
|
||||||
expect(fs.existsSync(path.join(dir, 'foobar/tests/example.spec.ts'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'foobar/package.json'))).toBeTruthy();
|
|
||||||
if (packageManager === 'npm')
|
|
||||||
expect(fs.existsSync(path.join(dir, 'foobar/package-lock.json'))).toBeTruthy();
|
|
||||||
else
|
|
||||||
expect(fs.existsSync(path.join(dir, 'foobar/yarn.lock'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'foobar/playwright.config.ts'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'foobar/.github/workflows/playwright.yml'))).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should generate a project with JavaScript and without GHA', async ({ run }) => {
|
|
||||||
const { exitCode, dir } = await run([], { installGitHubActions: false, testDir: 'tests', language: 'JavaScript', addExamples: false, installPlaywrightDependencies: true });
|
|
||||||
expect(exitCode).toBe(0);
|
|
||||||
expect(fs.existsSync(path.join(dir, 'tests/example.spec.js'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'package.json'))).toBeTruthy();
|
|
||||||
if (packageManager === 'npm')
|
|
||||||
expect(fs.existsSync(path.join(dir, 'package-lock.json'))).toBeTruthy();
|
|
||||||
else
|
|
||||||
expect(fs.existsSync(path.join(dir, 'yarn.lock'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'playwright.config.js'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, '.github/workflows/playwright.yml'))).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should generate be able to run the examples successfully', async ({ run }) => {
|
|
||||||
const { exitCode, dir, exec } = await run([], { installGitHubActions: false, testDir: 'tests', language: 'TypeScript', addExamples: true, installPlaywrightDependencies: true });
|
|
||||||
expect(exitCode).toBe(0);
|
|
||||||
expect(fs.existsSync(path.join(dir, 'tests/example.spec.ts'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'package.json'))).toBeTruthy();
|
|
||||||
|
|
||||||
expect(fs.existsSync(path.join(dir, 'playwright.config.ts'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'tests-examples/playwright.config.ts'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'tests-examples/server/index.js'))).toBeTruthy();
|
|
||||||
expect(fs.existsSync(path.join(dir, 'tests-examples/1-getting-started.spec.ts'))).toBeTruthy();
|
|
||||||
|
|
||||||
let result;
|
|
||||||
if (packageManager === 'npm')
|
|
||||||
result = await exec('npm', ['run', 'test:e2e-examples']);
|
|
||||||
else
|
|
||||||
result = await exec('yarn', ['test:e2e-examples']);
|
|
||||||
expect(result.code).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES2019",
|
|
||||||
"moduleResolution": "Node",
|
|
||||||
"downlevelIteration": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
},
|
|
||||||
"include": ["src"],
|
|
||||||
}
|
|
||||||
|
|
@ -21,6 +21,5 @@
|
||||||
"include": ["packages"],
|
"include": ["packages"],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"packages/*/lib",
|
"packages/*/lib",
|
||||||
"packages/create-playwright/",
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,8 +176,6 @@ for (const file of webPackFiles) {
|
||||||
for (const packageDir of packages) {
|
for (const packageDir of packages) {
|
||||||
if (!fs.existsSync(path.join(packageDir, 'src')))
|
if (!fs.existsSync(path.join(packageDir, 'src')))
|
||||||
continue;
|
continue;
|
||||||
if (path.basename(packageDir) === 'create-playwright')
|
|
||||||
continue;
|
|
||||||
steps.push({
|
steps.push({
|
||||||
command: 'npx',
|
command: 'npx',
|
||||||
args: [
|
args: [
|
||||||
|
|
@ -185,7 +183,7 @@ for (const packageDir of packages) {
|
||||||
...(watchMode ? ['-w', '--source-maps'] : []),
|
...(watchMode ? ['-w', '--source-maps'] : []),
|
||||||
'--extensions', '.ts',
|
'--extensions', '.ts',
|
||||||
'--out-dir', path.join(packageDir, 'lib'),
|
'--out-dir', path.join(packageDir, 'lib'),
|
||||||
'--ignore', '"packages/playwright-core/src/server/injected/**/*","packages/create-playwright/**/*"',
|
'--ignore', '"packages/playwright-core/src/server/injected/**/*"',
|
||||||
path.join(packageDir, 'src')],
|
path.join(packageDir, 'src')],
|
||||||
shell: true,
|
shell: true,
|
||||||
});
|
});
|
||||||
|
|
@ -262,12 +260,4 @@ if (lintMode) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// create-playwright package
|
|
||||||
steps.push({
|
|
||||||
command: 'npx',
|
|
||||||
args: ['ncc', 'build', 'cli.ts', (watchMode ? '--watch' : '--minify'), '--out', '../lib'],
|
|
||||||
shell: true,
|
|
||||||
cwd: 'packages/create-playwright/src'
|
|
||||||
});
|
|
||||||
|
|
||||||
watchMode ? runWatch() : runBuild();
|
watchMode ? runWatch() : runBuild();
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,6 @@ const PACKAGES = {
|
||||||
browsers: ['chromium', 'ffmpeg'],
|
browsers: ['chromium', 'ffmpeg'],
|
||||||
files: LICENSE_FILES,
|
files: LICENSE_FILES,
|
||||||
},
|
},
|
||||||
'create-playwright': {
|
|
||||||
browsers: [],
|
|
||||||
files: [],
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const dirtyFiles = [];
|
const dirtyFiles = [];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue