Skip to content

Commit 60dec77

Browse files
committed
[WIP] E2E Tests
1 parent dcad856 commit 60dec77

19 files changed

Lines changed: 423 additions & 85 deletions

File tree

.github/workflows/basic.yml

Lines changed: 186 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,18 @@ env:
1313
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
1414
TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
1515
BIGCOMMERCE_STORE_HASH: ${{ vars.BIGCOMMERCE_STORE_HASH }}
16-
BIGCOMMERCE_STOREFRONT_TOKEN: ${{ secrets.BIGCOMMERCE_STOREFRONT_TOKEN }}
1716
BIGCOMMERCE_CHANNEL_ID: ${{ vars.BIGCOMMERCE_CHANNEL_ID }}
17+
BIGCOMMERCE_CLIENT_ID: ${{ secrets.BIGCOMMERCE_CLIENT_ID }}
18+
BIGCOMMERCE_CLIENT_SECRET: ${{ secrets.BIGCOMMERCE_CLIENT_SECRET }}
19+
BIGCOMMERCE_STOREFRONT_TOKEN: ${{ secrets.BIGCOMMERCE_STOREFRONT_TOKEN }}
20+
BIGCOMMERCE_ACCESS_TOKEN: ${{ secrets.BIGCOMMERCE_ACCESS_TOKEN }}
21+
TEST_CUSTOMER_ID: ${{ vars.TEST_CUSTOMER_ID }}
22+
TEST_CUSTOMER_EMAIL: ${{ vars.TEST_CUSTOMER_EMAIL }}
23+
TEST_CUSTOMER_PASSWORD: ${{ secrets.TEST_CUSTOMER_PASSWORD }}
24+
TESTS_FALLBACK_LOCALE: ${{ vars.TESTS_FALLBACK_LOCALE }}
25+
TESTS_READ_ONLY: ${{ vars.TESTS_READ_ONLY }}
26+
DEFAULT_PRODUCT_ID: ${{ vars.DEFAULT_PRODUCT_ID }}
27+
DEFAULT_COMPLEX_PRODUCT_ID: ${{ vars.DEFAULT_COMPLEX_PRODUCT_ID }}
1828

1929
jobs:
2030
lint-typecheck:
@@ -75,3 +85,178 @@ jobs:
7585

7686
- name: Run Tests
7787
run: pnpm run test
88+
89+
e2e-tests:
90+
name: E2E Functional Tests
91+
92+
runs-on: ubuntu-latest
93+
94+
steps:
95+
- name: Checkout code
96+
uses: actions/checkout@v4
97+
with:
98+
fetch-depth: 2
99+
100+
- uses: pnpm/action-setup@v3
101+
102+
- name: Use Node.js
103+
uses: actions/setup-node@v4
104+
with:
105+
node-version-file: ".nvmrc"
106+
cache: "pnpm"
107+
108+
- name: Install dependencies
109+
run: pnpm install --frozen-lockfile
110+
111+
- name: Install Playwright browsers
112+
run: pnpm exec playwright install --with-deps chromium webkit
113+
working-directory: ./core
114+
115+
- name: Build catalyst-client
116+
run: pnpm --filter @bigcommerce/catalyst-client build
117+
118+
- name: Build catalyst-core
119+
run: pnpm --filter @bigcommerce/catalyst-core build
120+
121+
- name: Start server
122+
run: |
123+
pnpm start &
124+
npx wait-on http://localhost:3000 --timeout 60000
125+
working-directory: ./core
126+
env:
127+
PORT: 3000
128+
AUTH_SECRET: ${{ secrets.TESTS_AUTH_SECRET }}
129+
AUTH_TRUST_HOST: ${{ vars.TESTS_AUTH_TRUST_HOST }}
130+
BIGCOMMERCE_TRUSTED_PROXY_SECRET: ${{ secrets.BIGCOMMERCE_TRUSTED_PROXY_SECRET }}
131+
TESTS_LOCALE: ${{ vars.TESTS_LOCALE }}
132+
133+
- name: Run E2E tests
134+
run: pnpm exec playwright test tests/ui/e2e
135+
working-directory: ./core
136+
env:
137+
PLAYWRIGHT_TEST_BASE_URL: http://localhost:3000
138+
139+
- name: Upload test results
140+
if: ${{ !cancelled() }}
141+
uses: actions/upload-artifact@v4
142+
with:
143+
name: playwright-report
144+
path: ./core/.tests/reports/
145+
retention-days: 3
146+
147+
e2e-tests-no-trailing:
148+
name: E2E Functional Tests (TRAILING_SLASH=false)
149+
150+
runs-on: ubuntu-latest
151+
152+
steps:
153+
- name: Checkout code
154+
uses: actions/checkout@v4
155+
with:
156+
fetch-depth: 2
157+
158+
- uses: pnpm/action-setup@v3
159+
160+
- name: Use Node.js
161+
uses: actions/setup-node@v4
162+
with:
163+
node-version-file: ".nvmrc"
164+
cache: "pnpm"
165+
166+
- name: Install dependencies
167+
run: pnpm install --frozen-lockfile
168+
169+
- name: Install Playwright browsers
170+
run: pnpm exec playwright install --with-deps chromium
171+
working-directory: ./core
172+
173+
- name: Build catalyst-client
174+
run: pnpm --filter @bigcommerce/catalyst-client build
175+
176+
- name: Build catalyst-core
177+
run: pnpm --filter @bigcommerce/catalyst-core build
178+
179+
- name: Start server
180+
run: |
181+
pnpm start &
182+
npx wait-on http://localhost:3000 --timeout 60000
183+
working-directory: ./core
184+
env:
185+
PORT: 3000
186+
AUTH_SECRET: ${{ secrets.TESTS_AUTH_SECRET }}
187+
AUTH_TRUST_HOST: ${{ vars.TESTS_AUTH_TRUST_HOST }}
188+
BIGCOMMERCE_TRUSTED_PROXY_SECRET: ${{ secrets.BIGCOMMERCE_TRUSTED_PROXY_SECRET }}
189+
TESTS_LOCALE: ${{ vars.TESTS_LOCALE }}
190+
TRAILING_SLASH: false
191+
192+
- name: Run E2E tests
193+
run: pnpm exec playwright test tests/ui/e2e --grep @no-trailing-slash
194+
working-directory: ./core
195+
env:
196+
PLAYWRIGHT_TEST_BASE_URL: http://localhost:3000
197+
198+
- name: Upload test results
199+
if: ${{ !cancelled() }}
200+
uses: actions/upload-artifact@v4
201+
with:
202+
name: playwright-report-no-trailing
203+
path: ./core/.tests/reports/
204+
retention-days: 3
205+
206+
e2e-tests-alternate-locale:
207+
name: E2E Functional Tests (alternate locale)
208+
209+
runs-on: ubuntu-latest
210+
211+
steps:
212+
- name: Checkout code
213+
uses: actions/checkout@v4
214+
with:
215+
fetch-depth: 2
216+
217+
- uses: pnpm/action-setup@v3
218+
219+
- name: Use Node.js
220+
uses: actions/setup-node@v4
221+
with:
222+
node-version-file: ".nvmrc"
223+
cache: "pnpm"
224+
225+
- name: Install dependencies
226+
run: pnpm install --frozen-lockfile
227+
228+
- name: Install Playwright browsers
229+
run: pnpm exec playwright install --with-deps chromium
230+
working-directory: ./core
231+
232+
- name: Build catalyst-client
233+
run: pnpm --filter @bigcommerce/catalyst-client build
234+
235+
- name: Build catalyst-core
236+
run: pnpm --filter @bigcommerce/catalyst-core build
237+
238+
- name: Start server
239+
run: |
240+
pnpm start &
241+
npx wait-on http://localhost:3000 --timeout 60000
242+
working-directory: ./core
243+
env:
244+
PORT: 3000
245+
AUTH_SECRET: ${{ secrets.TESTS_AUTH_SECRET }}
246+
AUTH_TRUST_HOST: ${{ vars.TESTS_AUTH_TRUST_HOST }}
247+
BIGCOMMERCE_TRUSTED_PROXY_SECRET: ${{ secrets.BIGCOMMERCE_TRUSTED_PROXY_SECRET }}
248+
TESTS_LOCALE: ${{ vars.TESTS_ALTERNATE_LOCALE }}
249+
250+
- name: Run E2E tests
251+
run: pnpm exec playwright test tests/ui/e2e --grep @alternate-locale
252+
working-directory: ./core
253+
env:
254+
PLAYWRIGHT_TEST_BASE_URL: http://localhost:3000
255+
256+
- name: Upload test results
257+
if: ${{ !cancelled() }}
258+
uses: actions/upload-artifact@v4
259+
with:
260+
name: playwright-report-alternate-locale
261+
path: ./core/.tests/reports/
262+
retention-days: 3

core/playwright.config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default defineConfig({
2929
projects: [
3030
{
3131
name: 'tests-chromium',
32+
testIgnore: /.*\.mobile\.spec\.ts$/,
3233
use: {
3334
...devices['Desktop Chrome'],
3435
launchOptions: {
@@ -38,6 +39,14 @@ export default defineConfig({
3839
},
3940
},
4041
},
42+
{
43+
name: 'tests-webkit-mobile',
44+
testMatch: /.*\.mobile\.spec\.ts$/,
45+
use: {
46+
...devices['iPhone 11'],
47+
// WebKit doesn't support --disable-web-security
48+
},
49+
},
4150
],
42-
retries: 1,
51+
retries: 2,
4352
});

core/tests/fixtures/utils/api/subscribe/http.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import { testEnv } from '~/tests/environment';
2+
13
import { httpClient } from '../client';
24

35
import { SubscribeApi } from '.';
46

57
export const subscribeHttpClient: SubscribeApi = {
68
subscribe: async (email: string, firstName: string, lastName: string) => {
79
await httpClient.post('/v3/customers/subscribers', {
10+
channel_id: testEnv.BIGCOMMERCE_CHANNEL_ID ?? 1,
811
email,
912
first_name: firstName,
1013
last_name: lastName,

core/tests/tags.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
export const TAGS = {
22
// @writes-data is used to mark tests that modify data on the storefront without directly using the API.
33
writesData: '@writes-data',
4+
// @alternate-locale is used to mark tests that should be run with an alternate locale setting.
5+
alternateLocale: '@alternate-locale',
6+
// @no-trailing-slash is used to mark tests that should be run with TRAILING_SLASH disabled.
7+
noTrailingSlash: '@no-trailing-slash',
48
};

core/tests/ui/e2e/account/account.spec.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { defaultLocale } from '~/i18n/locales';
22
import { testEnv } from '~/tests/environment';
33
import { expect, test } from '~/tests/fixtures';
44
import { getTranslations } from '~/tests/lib/i18n';
5+
import { TAGS } from '~/tests/tags';
56

67
const accountUrls = [
78
'/account/orders',
@@ -18,14 +19,16 @@ accountUrls.forEach((url) => {
1819
});
1920

2021
accountUrls.forEach((url) => {
21-
test(`${url} is restricted for guest users when explicitly browsing to the locale URL`, async ({
22-
page,
23-
}) => {
24-
test.skip(testEnv.TESTS_LOCALE === defaultLocale);
22+
test(
23+
`${url} is restricted for guest users when explicitly browsing to the locale URL`,
24+
{ tag: TAGS.alternateLocale },
25+
async ({ page }) => {
26+
test.skip(testEnv.TESTS_LOCALE === defaultLocale);
2527

26-
await page.goto(`/${testEnv.TESTS_LOCALE}/${url}`);
27-
await expect(page).toHaveURL('/login/', { timeout: 1000 });
28-
});
28+
await page.goto(`/${testEnv.TESTS_LOCALE}/${url}`);
29+
await expect(page).toHaveURL('/login/', { timeout: 1000 });
30+
},
31+
);
2932
});
3033

3134
test('Account page displays the menu items for each section', async ({ page, customer }) => {

core/tests/ui/e2e/account/wishlist-details.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,12 @@ test('Wishlist details displays an out of stock product correctly', async ({
129129
page,
130130
catalog,
131131
customer,
132+
settings,
132133
}) => {
134+
await settings.setInventorySettings({ showOutOfStockMessage: true });
135+
133136
const product = await catalog.createSimpleProduct({
137+
inventoryTracking: 'product',
134138
inventoryLevel: 0,
135139
});
136140

core/tests/ui/e2e/account/wishlists.mobile.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ test('Share button calls navigator.share with the correct URL', async ({ page, c
3636
});
3737

3838
await page.goto('/account/wishlists/');
39+
await page.waitForLoadState('networkidle');
3940

4041
const locator = page.getByRole('region', { name });
4142

core/tests/ui/e2e/auth/login.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ test('JWT login redirects to the specified redirect_to value in the token payloa
8686

8787
await page.goto(`/login/token/${jwt}`);
8888
await page.waitForURL('/account/addresses/');
89-
await expect(page.getByRole('heading', { name: t('title') })).toBeVisible();
89+
await expect(page.getByRole('heading', { name: t('title'), exact: true })).toBeVisible();
9090
});
9191

9292
test('JWT login with an invalid/expired token shows an error message', async ({ page }) => {

core/tests/ui/e2e/auth/register.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ test('Registration works as expected', { tag: [TAGS.writesData] }, async ({ page
3737
await page.getByRole('combobox', { name: 'Country' }).click();
3838
await page.keyboard.type('United States');
3939
await page.keyboard.press('Enter');
40-
await page.getByRole('radio', { name: 'Home' }).click();
4140
await page.getByRole('button', { name: t('Auth.Register.cta') }).click();
4241

4342
await expect(page).toHaveURL('/account/orders/');
@@ -84,7 +83,6 @@ test('Registration fails if email is already in use', async ({ page, customer })
8483
await page.getByRole('combobox', { name: 'Country' }).click();
8584
await page.keyboard.type('United States');
8685
await page.keyboard.press('Enter');
87-
await page.getByRole('radio', { name: 'Home' }).click();
8886
await page.getByRole('button', { name: t('cta') }).click();
8987

9088
await expect(page).not.toHaveURL('/account/orders/');

core/tests/ui/e2e/blog.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ test('Blog is accessible and displays posts', async ({ page, blog }) => {
1313

1414
const breadcrumbs = page.getByLabel('breadcrumb');
1515

16-
await expect(breadcrumbs.getByText(t('home'))).toBeVisible();
17-
await expect(breadcrumbs.getByText(name)).toBeVisible();
16+
await expect(breadcrumbs.getByText(t('home')).first()).toBeVisible();
17+
await expect(breadcrumbs.getByText(name).first()).toBeVisible();
1818

1919
// eslint-disable-next-line @typescript-eslint/no-misused-promises
2020
posts.forEach(async (post) => {
2121
await expect(
22-
page.locator(`a[href*="${post.path}"]`).filter({ hasText: post.title }),
22+
page.locator(`a[href*="${post.path}"]`).filter({ hasText: post.title }).first(),
2323
).toBeVisible();
2424
});
2525
});

0 commit comments

Comments
 (0)