diff --git a/.env b/.env new file mode 100644 index 0000000..2394561 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +BASE_URL=https://hlk.meiguanjia.net +BOSS_ACCOUNT=17770720274 +BOSS_PASSWORD=a123456 \ No newline at end of file diff --git a/.gitignore b/.gitignore index e2f599e..a500565 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules/ /blob-report/ /playwright/.cache/ /.idea/ +/.auth/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..27600a4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,13 @@ +{ + "printWidth": 100, + "tabWidth": 4, + "semi": true, + "singleQuote": true, + "quoteProps": "consistent", + "trailingComma": "es5", + "bracketSpacing": true, + "arrowParens": "avoid", + "proseWrap": "never", + "endOfLine": "lf", + "embeddedLanguageFormatting": "off" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 95370a4..d5017c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "playwright", "version": "1.0.0", "license": "ISC", + "dependencies": { + "dotenv": "^16.4.5" + }, "devDependencies": { "@playwright/test": "^1.47.2", "@types/node": "^22.7.4" @@ -39,6 +42,18 @@ "undici-types": "~6.19.2" } }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz", diff --git a/package.json b/package.json index 56598c7..8614734 100644 --- a/package.json +++ b/package.json @@ -10,5 +10,8 @@ "devDependencies": { "@playwright/test": "^1.47.2", "@types/node": "^22.7.4" + }, + "dependencies": { + "dotenv": "^16.4.5" } } diff --git a/playwright.config.js b/playwright.config.js index 4208666..714e60b 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,79 +1,88 @@ // @ts-check const { defineConfig, devices } = require('@playwright/test'); - +const { resolve } = require('path'); /** * Read environment variables from file. * https://github.com/motdotla/dotenv */ -// require('dotenv').config({ path: path.resolve(__dirname, '.env') }); +require('dotenv').config({ path: resolve(__dirname, '.env') }); + +const boss_storageState = '.auth/boss_user.json'; /** * @see https://playwright.dev/docs/test-configuration */ module.exports = defineConfig({ - testDir: './tests', - /* Run tests in files in parallel */ - fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'html', - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://127.0.0.1:3000', + testDir: './tests', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', }, - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, + /* Configure projects for major browsers */ + projects: [ + // Setup project + { name: 'setup', testMatch: /.*\.setup\.js/ }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + storageState: boss_storageState, + }, + dependencies: ['setup'], + }, - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] }, + // }, + // + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - // }, - ], + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, - /* Run your local dev server before starting the tests */ - // webServer: { - // command: 'npm run start', - // url: 'http://127.0.0.1:3000', - // reuseExistingServer: !process.env.CI, - // }, + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, }); diff --git a/tests/common.ts b/tests/common.ts new file mode 100644 index 0000000..d82d158 --- /dev/null +++ b/tests/common.ts @@ -0,0 +1,29 @@ +import { Locator, Page } from "@playwright/test"; +import { test as base } from "@playwright/test"; + +type MyFixtures = { + homePage: HomePage; +}; + +export const test = base.extend({ + homePage: async ({ page }, use) => { + const homePage = new HomePage(page); + await use(homePage); + }, +}); + +class HomePage { + private page: Page; + private $start: Locator; + + constructor(page: Page) { + this.page = page; + this.$start = this.page.getByRole("link", { name: "Get started" }); + } + + async clickStart() { + await this.$start.click(); + } +} + +export { expect } from "@playwright/test"; diff --git a/tests/common.tsx b/tests/common.tsx deleted file mode 100644 index 195e7a3..0000000 --- a/tests/common.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Locator, Page } from "@playwright/test"; -import { test as base } from "@playwright/test"; - -type MyFixtures = { - homePage: HomePage; -}; - -export const test = base.extend({ - homePage: async ({ page }, use) => { - const homePage = new HomePage(page); - await use(homePage); - }, -}); - -class HomePage { - private page: Page; - private $start: Locator; - - constructor(page: Page) { - this.page = page; - this.$start = this.page.getByRole("link", { name: "Get started" }); - } - - async clickStart() { - await this.$start.click(); - } -} - -export { expect } from "@playwright/test"; diff --git a/tests/setup/boss_auth.setup.js b/tests/setup/boss_auth.setup.js new file mode 100644 index 0000000..02bda65 --- /dev/null +++ b/tests/setup/boss_auth.setup.js @@ -0,0 +1,22 @@ +import { test as setup, expect } from '@playwright/test'; + +const authFile = '.auth/boss_user.json'; + +setup('authenticate', async ({ page }) => { + const baseURL = process.env.BASE_URL; + const account = process.env.BOSS_ACCOUNT; + const password = process.env.BOSS_PASSWORD; + const $account = page.getByRole('textbox', { name: '请输入您的手机号码' }); + const $password = page.getByRole('textbox', { name: '请输入登录密码' }); + const $loginConfirm = page.getByRole('button', { name: /登\s录/ }); + + await page.goto(baseURL); + await $account.fill(account); + const $accountStatus = page.locator('form div').filter({ has: $account }).locator('span i').last(); + await expect($accountStatus).toHaveClass(/pass/); + await $password.fill(password); + await page.getByLabel('请同意慧来客隐私政策和用户协议').check(); + await $loginConfirm.click(); + await expect($loginConfirm).not.toBeVisible(); + await page.context().storageState({ path: authFile }); +}); \ No newline at end of file diff --git a/tests/testexample.spec.js b/tests/testexample.spec.js index 586bd8b..bf61d0b 100644 --- a/tests/testexample.spec.js +++ b/tests/testexample.spec.js @@ -1,14 +1,14 @@ // @ts-check -const { test, expect } = require("./common"); +const { test, expect } = require('./common'); -test("get started link", async ({ page, homePage }) => { - await page.goto("https://playwright.dev/"); +test('get started link', async ({ page, homePage }) => { + await page.goto(process.env.BASE_URL); - // Click the get started link. - // await page.getByRole('link', {name: 'Get started'}).click(); - await homePage.clickStart(); + // Click the get started link. + // await page.getByRole('link', {name: 'Get started'}).click(); + // await homePage.clickStart(); - // Expects page to have a heading with the name of Installation. - await expect(page.getByRole("heading", { name: "Installation" })).toBeVisible(); + await page.waitForTimeout(3000); + // Expects page to have a heading with the name of Installation. + await expect(page.getByRole('button', { name: /登\s录/ })).not.toBeVisible(); }); - \ No newline at end of file