diff --git a/.bazelignore b/.bazelignore index b1bb86434a98..a473d3ec0595 100644 --- a/.bazelignore +++ b/.bazelignore @@ -27,6 +27,7 @@ client/web-sveltekit/node_modules client/wildcard/node_modules internal/appliance/frontend/maintenance/node_modules +testing/e2e/node_modules cmd/symbols/internal/squirrel/test_repos/starlark # Generated by local tools diff --git a/client/web-sveltekit/BUILD.bazel b/client/web-sveltekit/BUILD.bazel index ef85ef103ee0..b28879357c26 100644 --- a/client/web-sveltekit/BUILD.bazel +++ b/client/web-sveltekit/BUILD.bazel @@ -162,17 +162,6 @@ compile_app( visibility = ["//client/web/dist:__pkg__"], ) -playwright_test_bin.playwright_test( - name = "playwright_install", - args = [ - "install", - ], - local = True, - tags = [ - "requires-network", - ], -) - PLAYWRIGHT_DEPS = [ "//client/web-sveltekit:node_modules/@playwright/test", "//client/web-sveltekit:node_modules/playwright", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e81f23fc6e1a..edd3734cbeb3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1848,6 +1848,19 @@ importers: schema: {} + testing/e2e: + dependencies: + playwright: + specifier: 1.46.0 + version: 1.46.0 + devDependencies: + '@playwright/test': + specifier: 1.46.0 + version: 1.46.0 + '@types/node': + specifier: 20.11.19 + version: 20.11.19 + packages: /@0no-co/graphql.web@1.0.4(graphql@15.4.0): @@ -18301,7 +18314,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: true optional: true /fsevents@2.3.3: @@ -23333,7 +23345,6 @@ packages: resolution: {integrity: sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==} engines: {node: '>=18'} hasBin: true - dev: true /playwright@1.46.0: resolution: {integrity: sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==} @@ -23343,7 +23354,6 @@ packages: playwright-core: 1.46.0 optionalDependencies: fsevents: 2.3.2 - dev: true /plur@4.0.0: resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4017ef4fec13..c68f3f002c09 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,3 +4,4 @@ packages: - '!client/cody-context-filters-test-dataset' - 'schema' - 'internal/appliance/frontend/maintenance' + - 'testing/e2e' diff --git a/testing/e2e/.gitignore b/testing/e2e/.gitignore new file mode 100644 index 000000000000..68c5d18f00dc --- /dev/null +++ b/testing/e2e/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/testing/e2e/BUILD.bazel b/testing/e2e/BUILD.bazel new file mode 100644 index 000000000000..52f1e46ca726 --- /dev/null +++ b/testing/e2e/BUILD.bazel @@ -0,0 +1,64 @@ +load("@npm//:defs.bzl", "npm_link_all_packages") +load("@npm//testing/e2e:@playwright/test/package_json.bzl", playwright_test_bin = "bin") + +npm_link_all_packages(name = "node_modules") + +PLAYWRIGHT_DEPS = [ + "//testing/e2e:node_modules/@playwright/test", + "//testing/e2e:node_modules/playwright", +] + +playwright_test_bin.playwright_test( + name = "e2e_test", + timeout = "long", + args = [ + "test", + "--config $(location playwright.config.ts)", + ], + data = glob( + [ + "tests/**/*.spec.ts", + ], + ) + [ + "playwright.config.ts", + "//dev/tools:chromium", + ] + PLAYWRIGHT_DEPS, + env = { + "CHROMIUM_BIN": "$(rootpath //dev/tools:chromium)", + "BAZEL": "1", + }, + tags = [ + "manual", # We never want normal CI runs to include this. + "no-cache", # Because those tests are meant to target a real live instance, that lives outside the inputs, there's no point in caching. + "requires-network", + ], +) + +# This should be a run, but I'm getting weird errors when I try. +# To reproduce, ...bin.playwright_test -> ...bin.playwright_binary and bazel run the target. +playwright_test_bin.playwright_test( + name = "e2e_test_ui", + timeout = "eternal", + args = [ + "test", + "--config $(location playwright.config.ts)", + "--ui", + ], + data = glob( + [ + "tests/**/*.spec.ts", + ], + ) + [ + "playwright.config.ts", + "//dev/tools:chromium", + ] + PLAYWRIGHT_DEPS, + env = { + "CHROMIUM_BIN": "$(rootpath //dev/tools:chromium)", + "BAZEL": "1", + }, + tags = [ + "manual", # We never want normal CI runs to include this. + "no-cache", # Because those tests are meant to target a real live instance, that lives outside the inputs, there's no point in caching. + "requires-network", + ], +) diff --git a/testing/e2e/package.json b/testing/e2e/package.json new file mode 100644 index 000000000000..4672f9b9d472 --- /dev/null +++ b/testing/e2e/package.json @@ -0,0 +1,18 @@ +{ + "name": "e2e", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "dependencies": { + "playwright": "1.46.0" + }, + "devDependencies": { + "@playwright/test": "1.46.0", + "@types/node": "20.11.19" + } +} diff --git a/testing/e2e/playwright.config.ts b/testing/e2e/playwright.config.ts new file mode 100644 index 000000000000..7d3eb2b52a7f --- /dev/null +++ b/testing/e2e/playwright.config.ts @@ -0,0 +1,83 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '.', + /* 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: 'list', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1: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'], + launchOptions: { + // When in CI, use bazel packaged linux chromium + executablePath: process.env.CHROMIUM_BIN, + }, + }, + }, + + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] }, + // }, + + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/testing/e2e/tests/demo/dotcom.spec.ts b/testing/e2e/tests/demo/dotcom.spec.ts new file mode 100644 index 000000000000..9404ffe1d187 --- /dev/null +++ b/testing/e2e/tests/demo/dotcom.spec.ts @@ -0,0 +1,46 @@ +import { test, expect } from '@playwright/test' + +const baseURL = 'https://sourcegraph.com' + +test.describe('search smoke tests', () => { + test.describe('react', () => { + test('has title', async ({ page }) => { + await page.goto(`${baseURL}/search`) + await expect(page).toHaveTitle('Sourcegraph') + }) + }) + + test.describe('svelte', () => { + const useSvelte = 'feat=web-next' + test('has title', async ({ page }) => { + await page.goto(`${baseURL}/search?${useSvelte}`) + await expect(page).toHaveTitle('Sourcegraph') + }) + + test('navigate to repo via search', async ({ page }) => { + await page.goto( + `${baseURL}/search?${useSvelte}&q=context:global+repo:sgtest/weird&patternType=keyword&sm=0` + ) + await page.getByRole('link', { name: 'sgtest/weird' }).click() + await page.waitForURL(`${baseURL}/github.com/sgtest/weird`) + }) + + test('navigate to repo at a specific branch via search', async ({ page }) => { + await page.goto( + `${baseURL}/search?${useSvelte}&q=context:global+repo:sgtest/weird%40main&patternType=keyword&sm=0` + ) + await page.getByRole('link', { name: 'sgtest/weird' }).click() + await page.waitForURL(`${baseURL}/github.com/sgtest/weird@main`) + }) + + test('navigate to a file via search', async ({ page }) => { + await page.goto( + `${baseURL}/search?${useSvelte}&q=context:global+repo:%5Egithub%5C.com/sgtest/weird%24%40af4f7a3be2ba4be3a1804302f0ff97f56ac8130d+file:ALLCAPS&patternType=keyword&sm=0` + ) + await page.getByRole('link', { name: 'ALLCAPS' }).click() + await page.waitForURL( + `${baseURL}/github.com/sgtest/weird@af4f7a3be2ba4be3a1804302f0ff97f56ac8130d/-/blob/filenames/ALLCAPS` + ) + }) + }) +}) diff --git a/testing/e2e/tests/demo/playwright-demo.spec.ts b/testing/e2e/tests/demo/playwright-demo.spec.ts new file mode 100644 index 000000000000..1ed94eb26ad8 --- /dev/null +++ b/testing/e2e/tests/demo/playwright-demo.spec.ts @@ -0,0 +1,18 @@ +import { test, expect } from '@playwright/test'; + +test('has title', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/Playwright/); +}); + +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Get started' }).click(); + + // Expects page to have a heading with the name of Installation. + await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); +}); diff --git a/testing/e2e/tests/utils/constants.ts b/testing/e2e/tests/utils/constants.ts new file mode 100644 index 000000000000..25ce711e32a4 --- /dev/null +++ b/testing/e2e/tests/utils/constants.ts @@ -0,0 +1 @@ +export const BASE_URL = 'https://sourcegraph.com'