bagisto-playwright-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Playwright Testing

Playwright 测试

Bagisto's end-to-end suites live in two independent Playwright projects, one per package, each with its own config, fixtures and page objects:
packages/Webkul/{Admin,Shop}/tests/e2e-pw/
├── playwright.config.ts    # testDir ./tests, workers 1, retries 0
├── setup.ts                # adminPage / shopPage fixtures
├── pages/                  # page objects (BasePage subclasses)
├── tests/                  # *.spec.ts, grouped by admin menu section
├── utils/                  # faker.ts, admin.ts (login)
└── data/                   # fixture files for uploads
Run from the package directory, never the repo root:
bash
cd packages/Webkul/Admin
npm install && npx playwright install --with-deps chromium
npx playwright test --config=tests/e2e-pw/playwright.config.ts
npx playwright test --config=tests/e2e-pw/playwright.config.ts -g "create a category"
Bagisto的端到端测试套件位于两个独立的Playwright项目中,每个包对应一个项目,各自拥有独立的配置、测试夹具和页面对象:
packages/Webkul/{Admin,Shop}/tests/e2e-pw/
├── playwright.config.ts    # testDir ./tests, workers 1, retries 0
├── setup.ts                # adminPage / shopPage fixtures
├── pages/                  # page objects (BasePage subclasses)
├── tests/                  # *.spec.ts, grouped by admin menu section
├── utils/                  # faker.ts, admin.ts (login)
└── data/                   # fixture files for uploads
需从包目录运行,切勿从仓库根目录运行:
bash
cd packages/Webkul/Admin
npm install && npx playwright install --with-deps chromium
npx playwright test --config=tests/e2e-pw/playwright.config.ts
npx playwright test --config=tests/e2e-pw/playwright.config.ts -g "create a category"

The base URL comes from
.env
, not
BASE_URL

基础URL来自
.env
,而非
BASE_URL

playwright.config.ts
loads the app's
.env
and reads
APP_URL
:
ts
baseURL: `${process.env.APP_URL}/`.replace(/\/+$/, "/")
Nothing in either project reads
BASE_URL
. The CI workflows set a
BASE_URL
env var and it is ignored — they work because the same step rewrites
APP_URL
in
.env
with
sed
. Passing
BASE_URL=…
on the command line does nothing; to point a run at another host, change
APP_URL
.
playwright.config.ts
会加载应用的
.env
文件,并读取**
APP_URL
**:
ts
baseURL: `${process.env.APP_URL}/`.replace(/\/+$/, "/")
两个项目中都不会读取
BASE_URL
。CI工作流会设置
BASE_URL
环境变量,但该变量会被忽略——CI能正常运行是因为同一步骤会用
sed
重写
.env
中的
APP_URL
。在命令行传入
BASE_URL=…
不会产生任何效果;若要指向其他主机,需修改
APP_URL

Reference files

参考文件

FileLoad when
authoring.mdWriting a new spec or page object — structure, fixtures, ACL tests, naming
troubleshooting.mdA test fails, hangs, or passes when it should not
文件加载时机
authoring.md编写新测试用例或页面对象时——涉及结构、测试夹具、ACL测试、命名规范
troubleshooting.md测试失败、挂起或出现误通过情况时

Non-negotiables

不可妥协的规则

  • The suite shares one database and does not roll back. Unlike Pest, an E2E run leaves every record it creates. Write assertions that survive that: scope to the row you created, never to a global count or a list position.
  • workers: 1
    ,
    retries: 0
    ,
    fullyParallel: false
    .
    Specs run in file order within a shard, so a spec that leaves the app in a changed state (a reordered list, a disabled record) affects the next one. Put the state back or assert only on what you made.
  • CI shards each project 10 ways (
    --shard=i/10
    ). A spec may not depend on another spec having run — shards split by file.
  • Admin auth is cached to
    .state/admin-auth.json
    by the
    adminPage
    fixture and reused across specs. Do not log in by hand in a spec.
  • Rebuild assets before running after any frontend change, or the browser loads the previous bundle and the failure will look like a test bug.
  • 测试套件共享一个数据库且不会回滚。 与Pest不同,E2E测试运行后会保留所有创建的记录。因此编写断言时需确保能适应这种情况:断言范围限定在你创建的行,切勿依赖全局计数或列表位置。
  • workers: 1
    retries: 0
    fullyParallel: false
    测试用例在分片内按文件顺序运行,因此若某个测试用例导致应用状态改变(如列表重排、记录禁用),会影响后续测试用例。需恢复状态或仅断言你创建的内容。
  • CI将每个项目拆分为10个分片
    --shard=i/10
    )。测试用例不得依赖其他测试用例的运行——分片是按文件拆分的。
  • 管理员认证信息会被缓存
    .state/admin-auth.json
    ,由
    adminPage
    测试夹具管理,并在所有测试用例中复用。切勿在测试用例中手动登录。
  • 前端变更后需重新构建资源再运行测试,否则浏览器会加载旧的资源包,导致失败看起来像是测试问题。

Writing a test — the shape

测试编写规范

ts
import { test } from "../../setup";
import { CategoryPage } from "../../pages/admin/catalog/CategoryPage";

test.describe("category management", () => {
    test("should create a category", async ({ adminPage }) => {
        const categoryPage = new CategoryPage(adminPage);

        await categoryPage.createCategory();
    });
});
The spec names the intent; the page object owns every locator. A spec that contains a CSS selector belongs in a page object instead — see authoring.md.
ts
import { test } from "../../setup";
import { CategoryPage } from "../../pages/admin/catalog/CategoryPage";

test.describe("category management", () => {
    test("should create a category", async ({ adminPage }) => {
        const categoryPage = new CategoryPage(adminPage);

        await categoryPage.createCategory();
    });
});
测试用例需明确意图;所有定位器都应由页面对象管理。若测试用例中包含CSS选择器,应将其移至页面对象中——详见authoring.md

Common mistakes

常见错误

  • Asserting a global count.
    meta.total
    , "the first row", "3 sections" — all break as soon as another spec adds a record. Assert on the named thing you created.
  • An unscoped locator that matches many rows. Every row of a list carries the same action markup, so
    getByText("Delete")
    resolves to N elements and fails strict mode. Scope to the row first.
  • Trusting a green new test. After writing a regression test, revert the fix and confirm it fails. On seeded data many assertions hold either way.
  • Assuming a Vue tile's accessible name is its label. Icon-font glyphs land in the accessible name, so
    getByRole("button", { name: "Static Content" })
    can match nothing. Target the label element.
  • Forgetting an open drawer or modal covers the page. Clicks on the list behind it are intercepted; close it first.
REQUIRED SUB-SKILL: Use bagisto-change-verification before calling any change done.
  • 断言全局计数。
    meta.total
    、“第一行”、“3个板块”——只要有其他测试用例添加记录,这些断言就会失效。应断言你创建的具体对象。
  • 使用未限定范围的定位器,匹配多行记录。 列表中的每一行都带有相同的操作标记,因此
    getByText("Delete")
    会匹配N个元素,导致严格模式下失败。需先限定行范围。
  • 轻信新测试显示的绿灯。 编写回归测试后,需还原修复内容并确认测试会失败。在有预置数据的情况下,很多断言无论是否修复都会成立。
  • 假设Vue磁贴的可访问名称就是其标签。 图标字体符号会被包含在可访问名称中,因此
    getByRole("button", { name: "Static Content" })
    可能无法匹配任何元素。应直接定位标签元素。
  • 忘记打开的抽屉或模态框会遮挡页面。 点击其后方的列表会被拦截;需先关闭它。
必备子技能: 在确认任何变更完成前,需使用bagisto-change-verification。