Skip to content

Commit

Permalink
Feat/fullstack playwright (#411)
Browse files Browse the repository at this point in the history
* feat: init playwright

* ci(e2e): add postgres service in github action

* ci(e2e): remove failing browser

Update reporter to use "github" one in CI

* feat: add utils to authenticate

update playwright config with default urls
remove gitlab component testings

* feat: update recommended extensions

* doc(e2e): update README.md

* fix: pnpm update

* wip: add target branch to test CI

* ci(e2e): use pnpm instead of yarn
  • Loading branch information
DecampsRenan authored Sep 26, 2023
1 parent be73792 commit 55fd688
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 4 deletions.
87 changes: 87 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Playwright Tests
on:
push:
branches: [main, master]
pull_request:
branches: [main, master, v2-going-full-stack]

jobs:
E2E:
timeout-minutes: 60
runs-on: ubuntu-latest
env:
NEXT_PUBLIC_BASE_URL: http://localhost:3000
NEXT_PUBLIC_DEV_ENV_NAME: tests
DATABASE_URL: postgres://startui:startui@localhost:5432/startui
NEXT_PUBLIC_IS_DEMO: false
AUTH_SECRET: Replace me with `openssl rand -base64 32` generated secret
EMAIL_SERVER: smtp://username:password@localhost:1025
EMAIL_FROM: Start UI <noreply@example.com>
services:
postgres:
image: postgres

env:
POSTGRES_PASSWORD: startui
POSTGRES_USER: startui
POSTGRES_DB: startui

options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: 18

- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 8
run_install: false

- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-${{ env.cache-name }}-
${{ runner.os }}-pnpm-store-
${{ runner.os }}-
- name: Install dependencies
run: pnpm install

- name: Install Playwright Browsers
run: pnpm playwright install --with-deps

- name: Migrate database
run: pnpm db:push

- name: Add default data into database
run: pnpm db:seed

- name: Run Playwright tests
run: pnpm e2e

- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ yarn-error.log*
# vercel
.vercel

# cypress
/cypress/videos

# Build info
.build-info.json
openapi.json
Expand All @@ -56,3 +53,8 @@ prisma/dev.db-journal

# Emails
.react-email

# playwright
/test-results/
/playwright-report/
/playwright/.cache/
4 changes: 3 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
"recommendations": [
"lokalise.i18n-ally",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
"esbenp.prettier-vscode",
"ms-playwright.playwright",
"Prisma.prisma"
]
}
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,17 @@ You can update the storage key used to detect the color mode by updating this co
export const COLOR_MODE_STORAGE_KEY = 'start-ui-color-mode'; // Update the key according to your needs
```

### E2E Tests

E2E tests are setup with Playwright.

```sh
pnpm e2e # Run tests in headless mode, this is the command executed in CI
pnpm e2e:ui # Open a UI which allow you to run specific tests and see test execution
```

Tests are written in the `e2e` folder; there is also a `e2e/utils` folder which contains some utils to help writing tests.

## Show hint on development environments

Setup the `NEXT_PUBLIC_DEV_ENV_NAME` env variable with the name of the environment.
Expand Down
28 changes: 28 additions & 0 deletions e2e/login.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { expect, test } from '@playwright/test';
import { getUtils } from 'e2e/utils';

test.describe('Authentication flow', () => {
test('Login as admin', async ({ page }) => {
const utils = getUtils(page);

await utils.loginAsAdmin();

await expect(
page.getByRole('heading', { name: 'Dashboard', level: 2 })
).toBeVisible();

await expect(page.getByRole('link', { name: 'Admin' })).toBeVisible();
});

test('Login as user', async ({ page }) => {
const utils = getUtils(page);

await utils.loginAsUser();

await expect(
page.getByRole('heading', { name: 'Dashboard', level: 2 })
).toBeVisible();

await expect(page.getByRole('link', { name: 'Admin' })).not.toBeVisible();
});
});
45 changes: 45 additions & 0 deletions e2e/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Page } from '@playwright/test';

/**
* Utilities constructor
*
* @example
* ```ts
* test.describe('My scope', () => {
* test('My test', async ({ page }) => {
* const utils = getUtils(page);
*
* // No need too pass page on each util
* await utils.login(...)
* })
* })
* ```
*/
export const getUtils = (page: Page) => {
return {
/**
* Utility used to authenticate the user on the app
*/
async login(userDetails: { email: string; password: string }) {
await page.goto('/login');
await page.waitForURL('**/login');

await page.getByLabel('Email').fill(userDetails.email);
await page.getByLabel(/^Password/).fill(userDetails.password);

await page.getByRole('button', { name: 'Log In' }).click();
},
async loginAsAdmin() {
return this.login({
email: 'admin@admin.com',
password: 'admin',
});
},
async loginAsUser() {
return this.login({
email: 'user@user.com',
password: 'user',
});
},
} as const;
};
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"storybook:build": "pnpm build:info && storybook build && mv ./storybook-static ./public/storybook",
"theme:generate-typing": "chakra-cli tokens ./src/theme/theme.ts",
"theme:generate-icons": "svgr --config-file src/components/Icons/svgr.config.js src/components/Icons/svg-sources",
"e2e": "playwright test",
"e2e:ui": "playwright test --ui",
"db:init": "docker run --name startui -e POSTGRES_PASSWORD=startui -e POSTGRES_USER=startui -e POSTGRES_DB=startui -p 5432:5432 -d postgres && sleep 10 && pnpm db:push && pnpm db:seed",
"db:start": "docker start startui",
"db:stop": "docker stop startui",
Expand Down Expand Up @@ -87,6 +89,7 @@
"@babel/parser": "7.22.16",
"@chakra-ui/cli": "2.4.1",
"@next/eslint-plugin-next": "13.5.2",
"@playwright/test": "1.38.1",
"@storybook/addon-actions": "7.4.5",
"@storybook/addon-essentials": "7.4.5",
"@storybook/addon-links": "7.4.5",
Expand Down
49 changes: 49 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { defineConfig, devices } from '@playwright/test';

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './e2e',
/* 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: process.env.CI ? 'github' : 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
baseURL: 'http://localhost: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'] },
},

{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],

/* Run your local dev server before starting the tests */
webServer: {
command: 'yarn dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
});
35 changes: 35 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 55fd688

Please sign in to comment.