Skip to content
This repository was archived by the owner on Dec 15, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a26d7b2
Install endform
jakst Nov 5, 2025
ec6b3ba
Modify playwright config
jakst Nov 5, 2025
d9eda83
TODO: Port works, but not URL
jakst Nov 5, 2025
1a25a87
Turn trace on
jakst Nov 8, 2025
b399dde
Cache assets
jakst Nov 8, 2025
0274215
Don't run playwright install
jakst Nov 8, 2025
ae439c4
Upgrade endform CLI
jakst Nov 8, 2025
24db1c1
Use endform CLI instead of Playwright
jakst Nov 8, 2025
fe87099
Remove extra flags from command
jakst Nov 8, 2025
1ce9f7c
Proxy network hosts
jakst Nov 8, 2025
fd9a082
More hosts
jakst Nov 8, 2025
0436cc7
One more
jakst Nov 8, 2025
d74d0fb
Endform API key
jakst Nov 10, 2025
19c71d2
No report
jakst Nov 10, 2025
668cafd
Order
jakst Nov 10, 2025
e7cce14
Pass env var through
jakst Nov 10, 2025
e5bedbd
Try with just installing ca-certificates package
jakst Nov 10, 2025
4f8da62
Proxy host 3ugvf97q49rve
jakst Nov 10, 2025
008cc51
With explicit port
jakst Nov 10, 2025
abc29d8
WITHOUT DAGGER START
jakst Nov 17, 2025
b784f72
don't set GRAFANA_URL
jakst Nov 17, 2025
c9a36d3
Formatting
jakst Nov 17, 2025
812d710
Make run
jakst Nov 17, 2025
be7ead0
180s timeout
jakst Nov 17, 2025
b38f34f
Grafana version
jakst Nov 17, 2025
2463034
Fewer tests
jakst Nov 17, 2025
4436753
Shorter timeouts
jakst Nov 17, 2025
5acf2f2
Log server output
jakst Nov 17, 2025
fab91ff
Fewer tests
jakst Nov 17, 2025
074a768
Build app
jakst Nov 18, 2025
85eef1c
Crank it up to 1/8
jakst Nov 18, 2025
9344361
Increase timeouts
jakst Nov 18, 2025
fc24a41
Crank it up to 1/2
jakst Nov 18, 2025
22d7f8a
Fix type imports
jakst Nov 18, 2025
ac8b949
Increase timeouts
jakst Nov 18, 2025
0389b89
Run 8/8 shards
jakst Nov 18, 2025
f09c9db
Try slower runners
jakst Nov 18, 2025
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
140 changes: 62 additions & 78 deletions .github/workflows/pr-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,101 +19,85 @@ env:
RUNNER_DEBUG: 1

jobs:
build-grafana:
name: Build & Package Grafana
runs-on: blacksmith-8vcpu-ubuntu-2404
run-playwright-tests:
name: Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }})
runs-on: blacksmith-2vcpu-ubuntu-2404
permissions:
contents: read

strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4, 5, 6, 7, 8]
shardTotal: [8]

steps:
- uses: actions/checkout@v5
with:
persist-credentials: false

# TODO: add a cleanup workflow to remove the cache when the PR is closed
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy
# TODO: maybe we could just use the cache to store the build, instead of uploading as an artifact?
- uses: actions/cache@v4
id: cache
- name: Setup Go
uses: actions/setup-go@v5
with:
key: "build-grafana-${{ runner.os }}-${{ hashFiles('yarn.lock', 'public/*', 'packages/*', 'conf/*', 'pkg/**/*.go', '**/go.mod', '**/go.sum', '!**_test.go', '!**.test.ts', '!**.test.tsx', 'Dockerfile') }}"
path: |
build-dir
go-version: "1.25.3"

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24.11.0"

# If no cache hit, build Grafana
- name: Build Grafana
if: steps.cache.outputs.cache-hit != 'true'
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
- name: Cache Node modules
uses: actions/cache@v4
with:
version: 0.18.8
verb: run
args: go run ./pkg/build/cmd artifacts -a targz:grafana:linux/amd64 -a docker:grafana:linux/amd64 --grafana-dir="${PWD}" > out.txt
- name: Cat built artifact
if: steps.cache.outputs.cache-hit != 'true'
run: cat out.txt
- name: Move built artifacts
if: steps.cache.outputs.cache-hit != 'true'
path: |
~/.npm
.yarn/cache
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install dependencies
run: |
mkdir -p build-dir
mv "$(grep 'grafana_.*tar.gz$' out.txt | grep -Fv -m1 'docker')" build-dir/grafana.tar.gz
mv "$(grep 'grafana_.*docker.tar.gz$' out.txt)" build-dir/grafana.docker.tar.gz
yarn install --frozen-lockfile

# If cache hit, validate the artifact is present
- name: Validate artifact
if: steps.cache.outputs.cache-hit == 'true'
- name: Build app
run: |
if [ ! -f build-dir/grafana.tar.gz ]; then
echo "Error: build-dir/grafana.tar.gz not found in cache"
exit 1
fi
yarn build

- name: Set artifact name
run: echo "artifact=grafana-server-${{github.run_number}}" >> "$GITHUB_OUTPUT"
id: artifact
- name: Build test plugins
run: |
yarn e2e:plugin:build

- name: Upload grafana.tar.gz
uses: actions/upload-artifact@v5
with:
retention-days: 1
name: grafana-tar-gz
path: build-dir/grafana.tar.gz
- name: Start Grafana server
run: |
make run > grafana-server.log 2>&1 &
GRAFANA_PID=$!
echo "GRAFANA_PID=$GRAFANA_PID" >> $GITHUB_ENV

- name: Upload grafana docker tarball
uses: actions/upload-artifact@v5
with:
retention-days: 1
name: grafana-docker-tar-gz
path: build-dir/grafana.docker.tar.gz
# Wait for Grafana to be ready
timeout 240 bash -c 'until curl -f http://localhost:3000/api/health; do sleep 2; done'

run-playwright-tests:
needs:
- build-grafana
name: Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }})
runs-on: blacksmith-8vcpu-ubuntu-2404
permissions:
contents: read
- name: Run E2E tests
run: |
export CI=true
export PLAYWRIGHT_HTML_OPEN=never
export PLAYWRIGHT_BLOB_OUTPUT_DIR=./blob-report
export ENDFORM_API_KEY=${{ secrets.ENDFORM_API_KEY }}

strategy:
fail-fast: false
matrix:
shard: [1]
shardTotal: [8]
yarn e2e:playwright --shard=${{ matrix.shard }}/${{ matrix.shardTotal }}

steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: actions/download-artifact@v6
with:
name: grafana-tar-gz
- name: Run E2E tests
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
with:
version: 0.18.8
verb: run
args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --shard=${{ matrix.shard }}/${{ matrix.shardTotal }} --blob-dir=./blob-report
- uses: actions/upload-artifact@v5
if: success() || failure()
- name: Stop Grafana server
if: always()
run: |
if [ -n "$GRAFANA_PID" ]; then
kill $GRAFANA_PID || true
fi

- name: Upload server logs
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-blob-${{ github.run_number }}-${{ matrix.shard }}
path: ./blob-report
retention-days: 1
name: server-logs-${{ matrix.shard }}
path: |
grafana-server.log
playwright-webserver.log
2 changes: 1 addition & 1 deletion e2e/old-arch/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { E2ESelectors, Selectors, selectors } from '@grafana/e2e-selectors';
import { type E2ESelectors, type Selectors, selectors } from '@grafana/e2e-selectors';

import * as flows from './flows';
import { e2eFactory } from './support';
Expand Down
2 changes: 1 addition & 1 deletion e2e/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { E2ESelectors, Selectors, selectors } from '@grafana/e2e-selectors';
import { type E2ESelectors, type Selectors, selectors } from '@grafana/e2e-selectors';

import * as flows from './flows';
import { e2eFactory } from './support';
Expand Down
3 changes: 3 additions & 0 deletions endform.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"proxyNetworkHosts": ["<loopback>", "*.dagger.local", "host.docker.internal", "*:3001", "10.87.0.25:3001", "3ugvf97q49rve", "3ugvf97q49rve:3001"]
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"e2e:enterprise": "./e2e/start-and-run-suite enterprise",
"e2e:enterprise:dev": "./e2e/start-and-run-suite enterprise dev",
"e2e:enterprise:debug": "./e2e/start-and-run-suite enterprise debug",
"e2e:playwright": "yarn playwright test --grep-invert @cloud-plugins",
"e2e:playwright": "yarn endform test --grep-invert @cloud-plugins",
"e2e:playwright:cloud-plugins": "yarn playwright test --grep @cloud-plugins",
"e2e:playwright:storybook": "yarn playwright test -c playwright.storybook.config.ts",
"e2e:acceptance": "yarn playwright test --grep @acceptance",
Expand Down Expand Up @@ -182,6 +182,7 @@
"cypress": "14.3.2",
"cypress-file-upload": "5.0.8",
"cypress-recurse": "^1.35.3",
"endform": "^0.45.12",
"enquirer": "^2.4.1",
"esbuild": "0.25.8",
"esbuild-loader": "4.3.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/grafana-e2e-selectors/src/selectors/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { resolveSelectors } from '../resolver';
import { E2ESelectors } from '../types';

import { versionedComponents, VersionedComponents } from './components';
import { versionedPages, VersionedPages } from './pages';
import { versionedComponents, type VersionedComponents } from './components';
import { versionedPages, type VersionedPages } from './pages';

const Pages = resolveSelectors(versionedPages);
const Components = resolveSelectors(versionedComponents);
Expand Down
13 changes: 5 additions & 8 deletions pkg/api/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -780,19 +780,16 @@ func (hs *HTTPServer) mapStatic(m *web.Mux, rootDir string, dir string, prefix s

if prefix == "public/build" {
headers = func(c *web.Context) {
c.Resp.Header().Set("Cache-Control", "public, max-age=31536000")
c.Resp.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
}
}

if hs.Cfg.Env == setting.Dev {
} else if prefix == "mockServiceWorker.js" {
headers = func(c *web.Context) {
c.Resp.Header().Set("Cache-Control", "max-age=0, must-revalidate, no-cache")
c.Resp.Header().Set("Content-Type", "application/javascript")
}
}

if prefix == "mockServiceWorker.js" {
} else if hs.Cfg.Env == setting.Dev {
headers = func(c *web.Context) {
c.Resp.Header().Set("Content-Type", "application/javascript")
c.Resp.Header().Set("Cache-Control", "max-age=0, must-revalidate, no-cache")
}
}

Expand Down
12 changes: 6 additions & 6 deletions pkg/build/e2e-playwright/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type RunTestOpts struct {
TestResultsExportDir string
PlaywrightCommand string
CloudPluginCreds *dagger.File
EndformAPIKey string
}

func RunTest(
Expand Down Expand Up @@ -56,6 +57,10 @@ func RunTest(
e2eContainer = e2eContainer.WithMountedFile("/tmp/outputs.json", opts.CloudPluginCreds)
}

if opts.EndformAPIKey != "" {
e2eContainer = e2eContainer.WithEnvVariable("ENDFORM_API_KEY", opts.EndformAPIKey)
}

e2eContainer = e2eContainer.WithExec(playwrightCommand, dagger.ContainerWithExecOpts{
Expect: dagger.ReturnTypeAny,
})
Expand Down Expand Up @@ -99,12 +104,7 @@ func buildPlaywrightCommand(opts RunTestOpts) []string {

playwrightExec := strings.Split(opts.PlaywrightCommand, " ")

playwrightCommand := append(playwrightExec,
"--reporter",
strings.Join(playwrightReporters, ","),
"--output",
testResultsDir,
)
playwrightCommand := playwrightExec

if opts.Shard != "" {
playwrightCommand = append(playwrightCommand, "--shard", opts.Shard)
Expand Down
2 changes: 2 additions & 0 deletions pkg/build/e2e-playwright/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func run(ctx context.Context, cmd *cli.Command) error {
htmlDir := cmd.String("html-dir")
blobDir := cmd.String("blob-dir")
playwrightCommand := cmd.String("playwright-command")
endformAPIKey := os.Getenv("ENDFORM_API_KEY")
// pa11yConfigPath := cmd.String("config")
// pa11yResultsPath := cmd.String("results")
// noThresholdFail := cmd.Bool("no-threshold-fail")
Expand Down Expand Up @@ -194,6 +195,7 @@ func run(ctx context.Context, cmd *cli.Command) error {
BlobReportExportDir: blobDir,
PlaywrightCommand: playwrightCommand,
CloudPluginCreds: cloudPluginCreds,
EndformAPIKey: endformAPIKey,
}

c, runErr := RunTest(ctx, d, runOpts)
Expand Down
16 changes: 5 additions & 11 deletions pkg/build/e2eutil/frontend_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ func WithFrontendContainer(ctx context.Context, d *dagger.Client, yarnHostSrc *d
}

nodeBase := WithNode(d, deps.NodeVersion)
playwrightBase := WithPlaywright(d, nodeBase, deps.PlaywrightVersion)

return WithYarnInstall(d, playwrightBase, yarnHostSrc), nil
return WithYarnInstall(d, nodeBase, yarnHostSrc), nil
}

func GetVersions(ctx context.Context, src *dagger.Directory) (Deps, error) {
Expand Down Expand Up @@ -56,15 +55,10 @@ func GetVersions(ctx context.Context, src *dagger.Directory) (Deps, error) {

func WithNode(d *dagger.Client, version string) *dagger.Container {
nodeImage := fmt.Sprintf("node:%s-slim", strings.TrimPrefix(version, "v"))
return d.Container().From(nodeImage)
}

func WithPlaywright(d *dagger.Client, base *dagger.Container, version string) *dagger.Container {
brCache := d.CacheVolume("playwright-browsers")
return base.
WithEnvVariable("PLAYWRIGHT_BROWSERS_PATH", "/playwright-cache").
WithMountedCache("/playwright-cache", brCache).
WithExec([]string{"npx", "-y", "playwright@" + version, "install", "--with-deps"})
return d.Container().From(nodeImage).
WithExec([]string{"apt-get", "update"}).
WithExec([]string{"apt-get", "install", "-y", "ca-certificates"}).
WithExec([]string{"rm", "-rf", "/var/lib/apt/lists/*"})
}

func WithYarnInstall(d *dagger.Client, base *dagger.Container, yarnHostSrc *dagger.Directory) *dagger.Container {
Expand Down
16 changes: 9 additions & 7 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export const testDirRoot = 'e2e-playwright';
const pluginDirRoot = path.join(testDirRoot, 'plugin-e2e');
export const DEFAULT_URL = 'http://localhost:3001';

process.env.GRAFANA_VERSION = '12.2.1';

export function withAuth(project: Project): Project {
project.dependencies ??= [];
project.use ??= {};
Expand All @@ -26,16 +28,15 @@ export const baseConfig: PlaywrightTestConfig<PluginOptions, {}> = {
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
reporter: [
['html'], // pretty
],
reporter: [['list']],
timeout: 120_000,
expect: {
timeout: 10_000,
timeout: 20_000,
},
use: {
...devices['Desktop Chrome'],
baseURL: process.env.GRAFANA_URL ?? DEFAULT_URL,
trace: 'retain-on-failure',
trace: 'on',
httpCredentials: {
username: 'admin',
password: 'admin',
Expand All @@ -50,10 +51,11 @@ export default defineConfig<PluginOptions>({
...baseConfig,
...(!process.env.GRAFANA_URL && {
webServer: {
command: 'yarn e2e:plugin:build && ./e2e-playwright/start-server',
url: DEFAULT_URL,
command: 'yarn e2e:plugin:build && ./e2e-playwright/start-server > playwright-webserver.log 2>&1',
port: 3001,
stdout: 'pipe',
stderr: 'pipe',
reuseExistingServer: true,
},
}),
projects: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { E2ESelectors } from '@grafana/e2e-selectors';
import type { E2ESelectors } from '@grafana/e2e-selectors';

export const components = {
configEditor: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { E2ESelectors } from '@grafana/e2e-selectors';
import type { E2ESelectors } from '@grafana/e2e-selectors';

export const components = {
queryEditor: {
Expand Down
Loading
Loading