Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: Initial E2E test framework for v2 #288

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 38 commits into from
Mar 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
470d06d
Add playwright dependency
bryphe-coder Feb 15, 2022
ab81ef9
Add initial playwright command to run against development server
bryphe-coder Feb 15, 2022
7c970b5
feat: Initial E2E framework
bryphe-coder Feb 15, 2022
853a2b9
Merge main
bryphe-coder Feb 28, 2022
2b0f0cb
Add test/e2e job
bryphe-coder Feb 28, 2022
78ceb9c
Add test/e2e job
bryphe-coder Feb 28, 2022
5243dea
Merge branch 'main' into bryphe/feat/initial-e2e-tests
bryphe-coder Feb 28, 2022
5eb9314
Use coderd directly, create initial user in setup script
bryphe-coder Feb 28, 2022
8fc553a
Ignore e2e tests from jest
bryphe-coder Feb 28, 2022
1b0e0d3
Fix typo
bryphe-coder Feb 28, 2022
f39f59a
Consolidate test_results/test-results
bryphe-coder Feb 28, 2022
0428a62
Add junit reporter for DataDog
bryphe-coder Feb 28, 2022
94c7684
Fix junit path
bryphe-coder Feb 28, 2022
dfe0c7c
Upload E2E test results to DataDog
bryphe-coder Feb 28, 2022
8af7d02
Formatting
bryphe-coder Feb 28, 2022
18f21da
Fix lint issues
bryphe-coder Feb 28, 2022
bcef4ac
Fix unit test DataDog uploads
bryphe-coder Feb 28, 2022
91bda34
Clean up globalSetup
bryphe-coder Feb 28, 2022
08dc699
Fix upload of E2E datadog reports
bryphe-coder Mar 1, 2022
b8cc80f
Add 'category' for classifying tests in datadog (unit, integration, e2e)
bryphe-coder Mar 1, 2022
a88a722
Remove coverage collection from E2E folder
bryphe-coder Mar 1, 2022
4bad40e
Run e2e on all platforms
bryphe-coder Mar 1, 2022
3b0b4cd
Try running on mac/ubuntu for now
bryphe-coder Mar 1, 2022
15a9a11
Experiment: Unblock windows e2e tests
bryphe-coder Mar 1, 2022
081c9cf
Revert "Experiment: Unblock windows e2e tests"
bryphe-coder Mar 1, 2022
439c13b
Revert change to test/js
bryphe-coder Mar 1, 2022
d7f9257
Add link back to Windows issue
bryphe-coder Mar 1, 2022
5eedfbe
Merge branch 'main' into bryphe/feat/initial-e2e-tests
bryphe-coder Mar 1, 2022
7381ca2
Consolidate test-results/test_results in .gitignore
bryphe-coder Mar 1, 2022
d3c8e50
Update site/.eslintignore
bryphe-coder Mar 1, 2022
e66c685
Switch to using const vs function
bryphe-coder Mar 1, 2022
bee5e25
Merge branch 'bryphe/feat/initial-e2e-tests' of github.com:coder/code…
bryphe-coder Mar 1, 2022
66b7d60
Refactor use email, password, username to constants
bryphe-coder Mar 2, 2022
7c568de
Expand POM model
bryphe-coder Mar 2, 2022
41a4516
Fix broken import
bryphe-coder Mar 2, 2022
7997a16
Merge branch 'main' into bryphe/feat/initial-e2e-tests
kylecarbs Mar 2, 2022
fae6b3f
Push functionality up to BasePOM API
bryphe-coder Mar 2, 2022
787213c
Merge branch 'main' into bryphe/feat/initial-e2e-tests
bryphe-coder Mar 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 71 additions & 2 deletions .github/workflows/coder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ jobs:
env:
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
DD_DATABASE: fake
DD_CATEGORY: unit
GIT_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: go run scripts/datadog-cireport/main.go gotests.xml

Expand Down Expand Up @@ -279,6 +280,74 @@ jobs:
if: (success() || failure()) && github.actor != 'dependabot[bot]'
env:
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
DD_DATABASE: postgresql
DD_CATEGORY: unit
GIT_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: go run scripts/datadog-cireport/main.go site/test-results/junit.xml

test-e2e:
name: "test/e2e/${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
# TODO: Get `make build` running on Windows 2022
# https://github.com/coder/coder/issues/384
# - windows-2022
steps:
- uses: actions/checkout@v2

- name: Cache Node
id: cache-node
uses: actions/cache@v2
with:
path: |
**/node_modules
.eslintcache
key: js-${{ runner.os }}-test-${{ hashFiles('**/yarn.lock') }}

# Go is required for uploading the test results to datadog
- uses: actions/setup-go@v2
with:
go-version: "^1.17"

- uses: hashicorp/setup-terraform@v1
with:
terraform_version: 1.1.2
terraform_wrapper: false

- uses: actions/setup-node@v3
with:
node-version: "14"

- uses: actions/cache@v2
with:
# Go mod cache, Linux build cache, Mac build cache, Windows build cache
path: |
~/go/pkg/mod
~/.cache/go-build
~/Library/Caches/go-build
%LocalAppData%\go-build
key: ${{ matrix.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.os }}-go-

- run: make build

- run: yarn playwright:install
working-directory: site

- run: yarn playwright:install-deps
working-directory: site

- run: yarn playwright:test
working-directory: site

- name: Upload DataDog Trace
if: (success() || failure()) && github.actor != 'dependabot[bot]' && runner.os == 'Linux'
env:
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
DD_CATEGORY: e2e
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kylecarbs - I added a new DataDog trait for test runs ("category") - intending to be one of unit | integration | e2e

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome!

GIT_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: go run scripts/datadog-cireport/main.go site/test_results/junit.xml
run: go run scripts/datadog-cireport/main.go site/test-results/junit.xml
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ site/.eslintcache
site/.next/
site/node_modules/
site/storybook-static/
site/test_results/
site/test-results/
site/yarn-error.log
coverage/

Expand Down
3 changes: 2 additions & 1 deletion scripts/datadog-cireport/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ func main() {
"service": "coder",
"_dd.cireport_version": "2",

"test.traits": fmt.Sprintf(`{"database":["%s"]}`, os.Getenv("DD_DATABASE")),
"test.traits": fmt.Sprintf(`{"database":["%s"], "category":["%s"]}`,
os.Getenv("DD_DATABASE"), os.Getenv("DD_CATEGORY")),

// Additional tags found in DataDog docs. See:
// https://docs.datadoghq.com/continuous_integration/setup_tests/junit_upload/#collecting-environment-configuration-metadata
Expand Down
2 changes: 1 addition & 1 deletion site/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ out
coverage
.next
storybook-static
test_results
test-results
2 changes: 1 addition & 1 deletion site/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ yarn-error.log
coverage/
out/
storybook-static/
test_results/
test-results/
5 changes: 5 additions & 0 deletions site/e2e/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Default credentials and user for running tests
export const username = "admin"
export const password = "password"
export const organization = "acme-crop"
export const email = "[email protected]"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bryphe-coder thanks for implementing this! 🎉

I def didn't mean for it to block the work, but it's a nice touch 🎊

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the great feedback & review @vapurrmaid !

24 changes: 24 additions & 0 deletions site/e2e/globalSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { FullConfig, request } from "@playwright/test"
import { email, username, password, organization } from "./constants"

const globalSetup = async (config: FullConfig): Promise<void> => {
// Grab the 'baseURL' from the webserver (`coderd`)
const { baseURL } = config.projects[0].use

// Create a context that will issue http requests.
const context = await request.newContext({
baseURL,
})

// Create initial user
await context.post("/api/v2/user", {
data: {
email,
username,
password,
organization,
},
})
}

export default globalSetup
27 changes: 27 additions & 0 deletions site/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as path from "path"
import { PlaywrightTestConfig } from "@playwright/test"

const config: PlaywrightTestConfig = {
testDir: "tests",
globalSetup: require.resolve("./globalSetup"),

// Create junit report file for upload to DataDog
reporter: [["junit", { outputFile: "test-results/junit.xml" }]],

use: {
baseURL: "http://localhost:3000",
video: "retain-on-failure",
},

// `webServer` tells Playwright to launch a test server - more details here:
// https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests
webServer: {
// Run the 'coderd' binary directly
command: path.join(__dirname, "../../bin/coderd"),
port: 3000,
timeout: 120 * 10000,
reuseExistingServer: false,
},
}

export default config
17 changes: 17 additions & 0 deletions site/e2e/pom/BasePom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Page } from "@playwright/test"

export abstract class BasePom {
protected readonly baseURL: string | undefined
protected readonly path: string
protected readonly page: Page

constructor(baseURL: string | undefined, path: string, page: Page) {
this.baseURL = baseURL
this.path = path
this.page = page
}

get url(): string {
return this.baseURL + this.path
}
}
8 changes: 8 additions & 0 deletions site/e2e/pom/ProjectsPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Page } from "@playwright/test"
import { BasePom } from "./BasePom"

export class ProjectsPage extends BasePom {
constructor(baseURL: string | undefined, page: Page) {
super(baseURL, "/projects", page)
}
}
14 changes: 14 additions & 0 deletions site/e2e/pom/SignInPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Page } from "@playwright/test"
import { BasePom } from "./BasePom"

export class SignInPage extends BasePom {
constructor(baseURL: string | undefined, page: Page) {
super(baseURL, "/login", page)
}

async submitBuiltInAuthentication(email: string, password: string): Promise<void> {
await this.page.fill("id=signin-form-inpt-email", email)
await this.page.fill("id=signin-form-inpt-password", password)
await this.page.click("id=signin-form-submit")
}
}
2 changes: 2 additions & 0 deletions site/e2e/pom/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./ProjectsPage"
export * from "./SignInPage"
16 changes: 16 additions & 0 deletions site/e2e/tests/login.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { test } from "@playwright/test"
import { ProjectsPage, SignInPage } from "../pom"
import { email, password } from "../constants"

test("Login takes user to /projects", async ({ baseURL, page }) => {
await page.goto(baseURL + "/", { waitUntil: "networkidle" })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting that unpacking the baseURL works here since it didn't in v1 - good sign! I believe you can avoid doing the string concatenation here though if you define url in the POM.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting that unpacking the baseURL works here since it didn't in v1 - good sign!

Yep! The v1 E2E tests use a special (external) address to point to the server under test (picked up from RUNTIME_CONFIG: https://github.com/coder/m/blob/833f23892c4802bfcdf9b39c86f415a1dc70a3b2/product/coder/e2e/configuration/runtime.ts#L18)

With these tests - using the webServer automatically populates the baseURL which is convenient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can avoid doing the string concatenation here though if you define url in the POM.

Good point - we have some more utilities in the POM layer in v1, I brought them over (ie, BasePOM) here in this change: 7c568de

It's a little bit awkward - since I'm passing both the baseURL and page into the POM's - let me know if you were thinking of a different approach!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented @vapurrmaid 's suggestions which help improve this in: fae6b3f - I'll merge what we have so the test is in place for the NextJS -> Webpack changes, but happy to iterate on it more

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bryphe-coder I'm definitely in favor of this merging sooner than later for iteration, it's in a really good starting spot!


// Log-in with the default credentials we set up in the development server
const signInPage = new SignInPage(baseURL, page)
await signInPage.submitBuiltInAuthentication(email, password)

const projectsPage = new ProjectsPage(baseURL, page)
await page.waitForNavigation({ url: projectsPage.url, waitUntil: "networkidle" })

await page.waitForSelector("text=Projects")
})
5 changes: 3 additions & 2 deletions site/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module.exports = {
},
testEnvironment: "jsdom",
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
testPathIgnorePatterns: ["/node_modules/", "/__tests__/fakes"],
testPathIgnorePatterns: ["/node_modules/", "/__tests__/fakes", "/e2e/"],
moduleDirectories: ["node_modules", "<rootDir>"],
},
{
Expand Down Expand Up @@ -45,6 +45,7 @@ module.exports = {
"!<rootDir>/api.ts",
"!<rootDir>/coverage/**/*.*",
"!<rootDir>/dev.ts",
"!<rootDir>/e2e/**/*.*",
"!<rootDir>/jest-runner.eslint.config.js",
"!<rootDir>/jest.config.js",
"!<rootDir>/next-env.d.ts",
Expand All @@ -58,7 +59,7 @@ module.exports = {
"jest-junit",
{
suiteName: "Front-end Jest Tests",
outputDirectory: "./test_results",
outputDirectory: "./test-results",
outputName: "junit.xml",
},
],
Expand Down
4 changes: 4 additions & 0 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
"format:write": "prettier --write '**/*.{css,html,js,json,jsx,md,ts,tsx,yaml,yml}' && sql-formatter -l postgresql ./database/query.sql -o ./database/query.sql",
"lint": "jest --selectProjects lint",
"lint:fix": "FIX=true yarn lint",
"playwright:install": "playwright install",
"playwright:install-deps": "playwright install-deps",
"playwright:test": "playwright test --config=e2e/playwright.config.ts",
"storybook": "start-storybook -p 6006 -s ./static",
"storybook:build": "build-storybook",
"test": "jest --selectProjects test",
Expand All @@ -21,6 +24,7 @@
"@material-ui/core": "4.9.4",
"@material-ui/icons": "4.5.1",
"@material-ui/lab": "4.0.0-alpha.42",
"@playwright/test": "1.17.2",
"@react-theming/storybook-addon": "1.1.5",
"@storybook/addon-actions": "6.4.19",
"@storybook/addon-essentials": "6.4.19",
Expand Down
Loading