Skip to content

Commit 08cb116

Browse files
committed
[WIP] E2E Tests
1 parent e5a03f6 commit 08cb116

File tree

15 files changed

+233
-37
lines changed

15 files changed

+233
-37
lines changed

.github/workflows/basic.yml

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,18 @@ env:
1212
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
1313
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
1414
TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
15-
BIGCOMMERCE_STORE_HASH: ${{ secrets.BIGCOMMERCE_STORE_HASH }}
15+
BIGCOMMERCE_STORE_HASH: ${{ vars.BIGCOMMERCE_STORE_HASH }}
16+
BIGCOMMERCE_CHANNEL_ID: ${{ vars.BIGCOMMERCE_CHANNEL_ID }}
17+
BIGCOMMERCE_CLIENT_ID: ${{ secrets.BIGCOMMERCE_CLIENT_ID }}
18+
BIGCOMMERCE_CLIENT_SECRET: ${{ secrets.BIGCOMMERCE_CLIENT_SECRET }}
1619
BIGCOMMERCE_STOREFRONT_TOKEN: ${{ secrets.BIGCOMMERCE_STOREFRONT_TOKEN }}
17-
BIGCOMMERCE_CHANNEL_ID: ${{ secrets.BIGCOMMERCE_CHANNEL_ID }}
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_LOCALE: ${{ vars.TESTS_LOCALE }}
25+
TESTS_FALLBACK_LOCALE: ${{ vars.TESTS_FALLBACK_LOCALE }}
26+
TESTS_READ_ONLY: ${{ vars.TESTS_READ_ONLY }}
1827

1928
jobs:
2029
lint-typecheck:
@@ -75,3 +84,63 @@ jobs:
7584

7685
- name: Run Tests
7786
run: pnpm run test
87+
88+
e2e-tests:
89+
name: E2E Functional Tests
90+
91+
runs-on: ubuntu-latest
92+
93+
steps:
94+
- name: Checkout code
95+
uses: actions/checkout@v4
96+
with:
97+
fetch-depth: 2
98+
99+
- uses: pnpm/action-setup@v3
100+
101+
- name: Use Node.js
102+
uses: actions/setup-node@v4
103+
with:
104+
node-version-file: ".nvmrc"
105+
cache: "pnpm"
106+
107+
- name: Install dependencies
108+
run: pnpm install --frozen-lockfile
109+
110+
- name: Install Playwright browsers
111+
run: pnpm exec playwright install --with-deps chromium
112+
working-directory: ./core
113+
114+
- name: Build catalyst-client
115+
run: pnpm --filter @bigcommerce/catalyst-client build
116+
117+
- name: Build catalyst-core
118+
run: pnpm --filter @bigcommerce/catalyst-core build
119+
120+
- name: Start server
121+
run: |
122+
pnpm start &
123+
npx wait-on http://localhost:3000 --timeout 60000
124+
working-directory: ./core
125+
env:
126+
PORT: 3000
127+
AUTH_SECRET: ${{ secrets.TESTS_AUTH_SECRET }}
128+
AUTH_TRUST_HOST: ${{ vars.TESTS_AUTH_TRUST_HOST }}
129+
BIGCOMMERCE_TRUSTED_PROXY_SECRET: ${{ secrets.BIGCOMMERCE_TRUSTED_PROXY_SECRET }}
130+
131+
- name: Run E2E tests
132+
run: pnpm exec playwright test tests/ui/e2e
133+
working-directory: ./core
134+
env:
135+
PLAYWRIGHT_TEST_BASE_URL: http://localhost:3000
136+
137+
# TODO: Add separate step to run TRAILING_SLASH=false tests via playwright tag filter
138+
# TODO: Add separate step to run tests with the alternate locale via playwright tag filter
139+
140+
- name: Upload test results
141+
if: ${{ !cancelled() }}
142+
uses: actions/upload-artifact@v4
143+
with:
144+
name: playwright-report
145+
path: ./core/.tests/reports/
146+
retention-days: 3

core/playwright.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,5 @@ export default defineConfig({
3939
},
4040
},
4141
],
42-
retries: 1,
42+
retries: 2,
4343
});

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/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/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
});

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ test('Cart page displays empty state when no items are in the cart', async ({ pa
88
await page.goto('/cart');
99

1010
await expect(page.getByRole('heading', { name: t('title') })).toBeVisible();
11-
await expect(page.getByText(t('Empty.title'))).toBeVisible();
12-
await expect(page.getByText(t('Empty.subtitle'))).toBeVisible();
11+
await expect(page.getByRole('heading', { name: t('Empty.title'), exact: true })).toBeVisible();
12+
await expect(page.getByText(t('Empty.subtitle')).first()).toBeVisible();
1313
await expect(page.getByRole('link', { name: t('Empty.cta') })).toBeVisible();
1414
});
1515

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,5 @@ test('Checkout works as a guest shopper', async ({ page, catalog }) => {
106106
// Complete order
107107
await page.locator('button[type="submit"]').click();
108108
await page.waitForLoadState('networkidle');
109-
110-
expect(page.url()).toContain('/checkout/order-confirmation');
109+
await page.waitForURL('**/checkout/order-confirmation', { timeout: 5000 });
111110
});

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ test('Validate compare page', async ({ page, catalog, currency }) => {
1414
await expect(page.getByRole('heading', { name: `${t('title')} 2` })).toBeVisible();
1515

1616
// Products names
17-
await expect(page.getByText(product.name, { exact: true })).toBeVisible();
18-
await expect(page.getByText(productWithVariants.name, { exact: true })).toBeVisible();
17+
await expect(page.getByText(product.name, { exact: true }).first()).toBeVisible();
18+
await expect(page.getByText(productWithVariants.name, { exact: true }).first()).toBeVisible();
1919

2020
// Products CTAs
2121
await expect(page.getByRole('button', { name: t('addToCart') })).toBeVisible();
@@ -32,8 +32,8 @@ test('Validate compare page', async ({ page, catalog, currency }) => {
3232
currency: defaultCurrency,
3333
});
3434

35-
await expect(page.getByText(productPrice)).toBeVisible();
36-
await expect(page.getByText(productWithVariantsPrice)).toBeVisible();
35+
await expect(page.getByText(productPrice, { exact: true }).first()).toBeVisible();
36+
await expect(page.getByText(productWithVariantsPrice, { exact: true }).first()).toBeVisible();
3737
});
3838

3939
test('Validate compare page with alternate currency', async ({ page, catalog, currency }) => {
@@ -143,5 +143,5 @@ test('Show empty state when no products are selected', async ({ page }) => {
143143

144144
await page.goto('/compare');
145145

146-
await expect(page.getByText(t('noProductsToCompare'))).toBeVisible();
146+
await expect(page.getByText(t('noProductsToCompare')).first()).toBeVisible();
147147
});

0 commit comments

Comments
 (0)