mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:31:48 +00:00
bazel: add integration test target (#49279)
Adds client integration tests target, got it running locally and disabled it for CI until the $DISPLAY issue is resolved. ## Test plan 1. `bazel test //client/web/src/integration:integration-tests` 2. [The CI build with Bazel checks](https://buildkite.com/sourcegraph/sourcegraph/builds/210860) ✅
This commit is contained in:
parent
9e0902a497
commit
627f5a6758
@ -23,7 +23,10 @@ export const ROOT_PATH = IS_BAZEL ? process.cwd() : resolveWithSymlink(__dirname
|
||||
export const WORKSPACES_PATH = resolveWithSymlink(ROOT_PATH, 'client')
|
||||
export const NODE_MODULES_PATH = resolveWithSymlink(ROOT_PATH, 'node_modules')
|
||||
export const MONACO_EDITOR_PATH = resolveWithSymlink(NODE_MODULES_PATH, 'monaco-editor')
|
||||
export const STATIC_ASSETS_PATH = resolveWithSymlink(ROOT_PATH, 'ui/assets')
|
||||
export const STATIC_ASSETS_PATH = resolveWithSymlink(
|
||||
ROOT_PATH,
|
||||
IS_BAZEL && process.env.WEB_BUNDLE_PATH ? process.env.WEB_BUNDLE_PATH : 'ui/assets'
|
||||
)
|
||||
|
||||
function getWorkspaceNodeModulesPaths(): string[] {
|
||||
const workspaces = fs.readdirSync(WORKSPACES_PATH)
|
||||
|
||||
1
client/shared/BUILD.bazel
generated
1
client/shared/BUILD.bazel
generated
@ -347,7 +347,6 @@ ts_project(
|
||||
"//:node_modules/@types/node",
|
||||
"//:node_modules/@types/puppeteer",
|
||||
"//:node_modules/@types/react",
|
||||
"//:node_modules/axe-core", #keep
|
||||
"//:node_modules/classnames",
|
||||
"//:node_modules/comlink",
|
||||
"//:node_modules/core-js",
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
* https://github.com/davidNHK/pollyjs/blob/3e876a8cc0b28e8ef422763762bdab10027bb25d/packages/%40pollyjs/core/src/-private/logger.js
|
||||
*
|
||||
*/
|
||||
if (process.env.CI) {
|
||||
if (process.env.CI || process.env.LOG_BROWSER_CONSOLE === 'false') {
|
||||
const originalLog = console.log
|
||||
const originalError = console.error
|
||||
const originalGroup = console.group
|
||||
|
||||
1
client/shared/src/testing/BUILD.bazel
generated
1
client/shared/src/testing/BUILD.bazel
generated
@ -80,6 +80,7 @@ ts_project(
|
||||
"//:node_modules/@types/react",
|
||||
"//:node_modules/@types/sinon",
|
||||
"//:node_modules/@types/uuid",
|
||||
"//:node_modules/axe-core", #keep
|
||||
"//:node_modules/chalk",
|
||||
"//:node_modules/date-fns",
|
||||
"//:node_modules/delay",
|
||||
|
||||
@ -47,10 +47,10 @@ export const oncePageEvent = <E extends keyof PageEventObject>(page: Page, event
|
||||
|
||||
export const extractStyles = (page: puppeteer.Page): Promise<string> =>
|
||||
page.evaluate(() =>
|
||||
[...document.styleSheets].reduce(
|
||||
Array.from(document.styleSheets).reduce(
|
||||
(styleSheetRules, styleSheet) =>
|
||||
styleSheetRules.concat(
|
||||
[...styleSheet.cssRules].reduce((rules, rule) => rules.concat(rule.cssText), '')
|
||||
Array.from(styleSheet.cssRules).reduce((rules, rule) => rules.concat(rule.cssText), '')
|
||||
),
|
||||
''
|
||||
)
|
||||
@ -147,9 +147,18 @@ function findElementRegexpStrings(
|
||||
}
|
||||
|
||||
function findElementMatchingRegexps(tag: string, regexps: string[]): HTMLElement | null {
|
||||
for (const regexpString of regexps) {
|
||||
const regexp = new RegExp(regexpString)
|
||||
for (const element of document.querySelectorAll<HTMLElement>(tag)) {
|
||||
// This method is invoked via puppeteer.Page.eval* and runs in the browser context.
|
||||
// This method must not use anything outside its own scope such as variables or functions,
|
||||
// including babel helpers from transpilation. Therefore this method must be written in
|
||||
// legacy-compatible JavaScript.
|
||||
const elements = document.querySelectorAll<HTMLElement>(tag)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||
for (let regexI = 0; regexI < regexps.length; regexI++) {
|
||||
const regexp = new RegExp(regexps[regexI])
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||
for (let elementI = 0; elementI < elements.length; elementI++) {
|
||||
const element = elements[elementI]
|
||||
if (!element.offsetParent) {
|
||||
// Ignore hidden elements
|
||||
continue
|
||||
@ -509,9 +518,7 @@ export class Driver {
|
||||
}
|
||||
|
||||
public async paste(value: string): Promise<void> {
|
||||
await this.page.evaluate(async (value: string) => {
|
||||
await navigator.clipboard.writeText(value)
|
||||
}, value)
|
||||
await this.page.evaluate((value: string) => navigator.clipboard.writeText(value), value)
|
||||
const modifier = os.platform() === 'darwin' ? Key.Meta : Key.Control
|
||||
await this.page.keyboard.down(modifier)
|
||||
await this.page.keyboard.press('v')
|
||||
|
||||
11
client/web/BUILD.bazel
generated
11
client/web/BUILD.bazel
generated
@ -4,7 +4,7 @@ load("@npm//:defs.bzl", "npm_link_all_packages")
|
||||
load("//client/shared/dev:generate_graphql_operations.bzl", "generate_graphql_operations")
|
||||
load("//client/shared/dev:tools.bzl", "module_style_typings")
|
||||
load("//dev:defs.bzl", "jest_test", "npm_package", "sass", "ts_project")
|
||||
load("//dev:webpack.bzl", "webpack_bundle", "webpack_devserver")
|
||||
load("//dev:webpack.bzl", "webpack_bundle", "webpack_devserver", "webpack_web_app")
|
||||
|
||||
# TODO(bazel): storybook build
|
||||
# gazelle:exclude **/*.story.{ts,tsx}
|
||||
@ -1939,8 +1939,8 @@ ENTERPRISE_BUNDLE_DATA_DEPS = BUNDLE_DATA_DEPS + [
|
||||
]
|
||||
]
|
||||
|
||||
webpack_bundle(
|
||||
name = "bundle-enterprise",
|
||||
webpack_web_app(
|
||||
name = "app-enterprise",
|
||||
srcs = ENTERPRISE_BUNDLE_DATA_DEPS + [
|
||||
"//:babel_config",
|
||||
"//:browserslist",
|
||||
@ -1951,8 +1951,11 @@ webpack_bundle(
|
||||
},
|
||||
env = {
|
||||
"NODE_ENV": "production",
|
||||
"ENTERPRISE": "true",
|
||||
"INTEGRATION_TESTS": "true",
|
||||
},
|
||||
output_dir = True,
|
||||
visibility = ["//client/web:__subpackages__"],
|
||||
webpack_config = "webpack.bazel.config.js",
|
||||
deps = WEBPACK_CONFIG_DEPS,
|
||||
)
|
||||
@ -1984,6 +1987,6 @@ build_test(
|
||||
name = "webpack_test",
|
||||
targets = [
|
||||
":bundle",
|
||||
":bundle-enterprise",
|
||||
":app-enterprise",
|
||||
],
|
||||
)
|
||||
|
||||
@ -66,7 +66,7 @@ describe('Repository component', () => {
|
||||
await driver.page.waitForSelector(selector, { visible: true })
|
||||
return driver.page.evaluate(() =>
|
||||
// You can't reference hoverContentSelector in puppeteer's driver.page.evaluate
|
||||
[...document.querySelectorAll('.test-tooltip-content')].map(content => content.textContent || '')
|
||||
Array.from(document.querySelectorAll('.test-tooltip-content')).map(content => content.textContent || '')
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
12
client/web/src/integration/BUILD.bazel
generated
12
client/web/src/integration/BUILD.bazel
generated
@ -1,5 +1,6 @@
|
||||
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")
|
||||
load("//dev:defs.bzl", "ts_project")
|
||||
load("//dev:mocha.bzl", "mocha_test")
|
||||
|
||||
# integration/ does not contain a src/
|
||||
# gazelle:js_files **/*.{ts,tsx}
|
||||
@ -99,3 +100,14 @@ ts_project(
|
||||
"//client/web:node_modules/@sourcegraph/shared",
|
||||
],
|
||||
)
|
||||
|
||||
mocha_test(
|
||||
name = "integration-tests",
|
||||
data = ["//client/web:app-enterprise"],
|
||||
env = {
|
||||
"WEB_BUNDLE_PATH": "$(rootpath //client/web:app-enterprise)",
|
||||
},
|
||||
tags = ["manual"],
|
||||
tests = [test.replace(".ts", ".js") for test in glob(["**/*.test.ts"])],
|
||||
deps = [":integration_tests"],
|
||||
)
|
||||
|
||||
@ -13,14 +13,19 @@ NON_BUNDLED = [
|
||||
"node-fetch",
|
||||
"console",
|
||||
|
||||
# UMD modules
|
||||
"jsonc-parser",
|
||||
|
||||
# Dependencies with bundling issues
|
||||
"jsonc-parser"
|
||||
"@sourcegraph/build-config",
|
||||
]
|
||||
|
||||
# ... some of which are needed at runtime
|
||||
NON_BUNDLED_DEPS = [
|
||||
"//:node_modules/jsonc-parser",
|
||||
"//:node_modules/puppeteer",
|
||||
"//:node_modules/axe-core",
|
||||
"//client/web:node_modules/@sourcegraph/build-config",
|
||||
]
|
||||
|
||||
def mocha_test(name, tests, deps = [], args = [], data = [], env = {}, **kwargs):
|
||||
@ -32,7 +37,7 @@ def mocha_test(name, tests, deps = [], args = [], data = [], env = {}, **kwargs)
|
||||
testonly = True,
|
||||
entry_points = tests,
|
||||
platform = "node",
|
||||
target = "node12",
|
||||
target = "esnext",
|
||||
output_dir = True,
|
||||
external = NON_BUNDLED,
|
||||
sourcemap = "linked",
|
||||
@ -52,7 +57,7 @@ def mocha_test(name, tests, deps = [], args = [], data = [], env = {}, **kwargs)
|
||||
"$(location //:mocha_config)",
|
||||
"$(location :%s)/**/*.test.js" % bundle_name,
|
||||
] + args,
|
||||
data = data + deps + [
|
||||
data = data + [
|
||||
":%s" % bundle_name,
|
||||
"//:mocha_config",
|
||||
] + NON_BUNDLED_DEPS,
|
||||
@ -67,11 +72,16 @@ def mocha_test(name, tests, deps = [], args = [], data = [], env = {}, **kwargs)
|
||||
"SOURCEGRAPH_BASE_URL": "https://sourcegraph.test:3443",
|
||||
"GH_TOKEN": "fake-gh-token",
|
||||
"SOURCEGRAPH_SUDO_TOKEN": "fake-sg-token",
|
||||
"NO_CLEANUP": "true",
|
||||
"KEEP_BROWSER": "true",
|
||||
"DEVTOOLS": "true",
|
||||
"NO_CLEANUP": "false",
|
||||
"KEEP_BROWSER": "false",
|
||||
"DEVTOOLS": "false",
|
||||
"BROWSER": "chrome",
|
||||
"WINDOW_WIDTH": "1920",
|
||||
"WINDOW_HEIGHT": "1080",
|
||||
"LOG_BROWSER_CONSOLE": "false",
|
||||
|
||||
# Puppeteer config
|
||||
"DISPLAY": ":1",
|
||||
}),
|
||||
tags = ["manual"],
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
load("@aspect_rules_webpack//webpack:defs.bzl", _webpack_bundle = "webpack_bundle", _webpack_devserver = "webpack_devserver")
|
||||
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
|
||||
|
||||
def webpack_bundle(name, **kwargs):
|
||||
_webpack_bundle(
|
||||
@ -7,6 +8,24 @@ def webpack_bundle(name, **kwargs):
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def webpack_web_app(name, **kwargs):
|
||||
bundle_name = "%s_bundle" % name
|
||||
|
||||
_webpack_bundle(
|
||||
name = bundle_name,
|
||||
webpack = "//dev:webpack",
|
||||
**kwargs
|
||||
)
|
||||
|
||||
copy_to_directory(
|
||||
name = name,
|
||||
# flatten static assets
|
||||
# https://docs.aspect.build/rules/aspect_bazel_lib/docs/copy_to_directory/#root_paths
|
||||
root_paths = ["ui/assets", "client/web/%s" % bundle_name],
|
||||
srcs = ["//ui/assets/img:img", ":%s" % bundle_name],
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
def webpack_devserver(name, **kwargs):
|
||||
_webpack_devserver(
|
||||
name = name,
|
||||
|
||||
@ -38,6 +38,10 @@ Additional `BUILD.bazel` files may exist throughout subdirectories and is encour
|
||||
|
||||
All client tests (of all types such as jest and mocha) can be invoked by `bazel test //client/...` or individual tests can be specified such as `bazel test //client/common:test` or `bazel test //client/web/src/end-to-end:e2e`. Jest tests can be debugged using `bazel run --config=debug //client/common:test`.
|
||||
|
||||
### Notes
|
||||
|
||||
Currently, it's impossible to use features that Babel will transpile, creating helper methods inside Puppeteer `driver.page.evaluate` calls. E.g., the `for-of` syntax transpiled by Babel creates a helper in the module's top-level scope and uses it in the `evaluate` call. But since the contents of the `evaluate` call are passed to the `eval` function inside Puppeteer, it doesn't have the reference to the created helper and fails in the runtime. This is caused by the fact that we uniformly transform all TS files to JS using Babel in Bazel. We will develop an approach that would allow skipping the Babel transpilation step for files executed only in the node environment.
|
||||
|
||||
## Bundling
|
||||
|
||||
The primary `client/web` bundle targets are:
|
||||
|
||||
1
ui/assets/img/BUILD.bazel
generated
1
ui/assets/img/BUILD.bazel
generated
@ -1,4 +1,5 @@
|
||||
filegroup(
|
||||
name = "img",
|
||||
srcs = glob(["**/*.*"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user