Skip to content

Commit 8cdd4f4

Browse files
authored
feat: e2e workflow, auth test (#3050)
1 parent b16b226 commit 8cdd4f4

22 files changed

+843
-53
lines changed

.devcontainer/devcontainer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050
"lokalise.i18n-ally",
5151
"formulahendry.auto-close-tag",
5252
"formulahendry.auto-rename-tag",
53-
"github.vscode-pull-request-github"
53+
"github.vscode-pull-request-github",
54+
"redhat.vscode-yaml"
5455
]
5556
}
5657
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
services:
2+
apisix:
3+
ports:
4+
- '9180:9180/tcp'
5+
- '9080:9080/tcp'
6+
- '9091:9091/tcp'
7+
- '9443:9443/tcp'
8+
etcd:
9+
ports:
10+
- '2379:2379/tcp'

.devcontainer/docker-compose.yml

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
include:
2+
- path:
3+
- ../e2e/server/docker-compose.common.yml
4+
- docker-compose.override.yml
15
services:
26
apisix-dashboard:
37
build:
@@ -11,40 +15,3 @@ services:
1115
ports:
1216
- '5173:5173'
1317
- '5174:5174'
14-
15-
apisix:
16-
image: 'apache/apisix:3.12.0-debian'
17-
restart: always
18-
volumes:
19-
- ./apisix_conf.yml:/usr/local/apisix/conf/config.yaml:ro
20-
depends_on:
21-
- etcd
22-
ports:
23-
- '9180:9180/tcp'
24-
- '9080:9080/tcp'
25-
- '9091:9091/tcp'
26-
- '9443:9443/tcp'
27-
networks:
28-
- apisix
29-
30-
etcd:
31-
image: bitnami/etcd:3.5
32-
restart: always
33-
volumes:
34-
- etcd_data:/bitnami/etcd
35-
environment:
36-
ETCD_ENABLE_V2: 'true'
37-
ALLOW_NONE_AUTHENTICATION: 'yes'
38-
ETCD_ADVERTISE_CLIENT_URLS: 'http://etcd:2379'
39-
ETCD_LISTEN_CLIENT_URLS: 'http://0.0.0.0:2379'
40-
ports:
41-
- '2379:2379/tcp'
42-
networks:
43-
- apisix
44-
45-
networks:
46-
apisix:
47-
driver: bridge
48-
49-
volumes:
50-
etcd_data:

.github/workflows/e2e.yml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: Frontend e2e test
2+
3+
on:
4+
push:
5+
branches:
6+
- "**"
7+
pull_request:
8+
types: [labeled, synchronize]
9+
branches:
10+
- "**"
11+
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
test:
18+
if: ${{ contains(github.event.pull_request.labels.*.name, 'e2e-test') }}
19+
timeout-minutes: 40
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- name: Get PR Labels
25+
id: get-labels
26+
uses: actions/github-script@v6
27+
with:
28+
script: |
29+
const labels = context.payload.pull_request.labels.map(label => label.name);
30+
core.setOutput("labels", labels.join(","));
31+
- name: Set image label as environment variable
32+
run: |
33+
export LABELS=${{ steps.get-labels.outputs.labels }}
34+
echo "LABELS=${LABELS}" >> $GITHUB_ENV
35+
shell: bash
36+
37+
# ensure this in https://github.com/apache/infrastructure-actions/blob/main/actions.yml
38+
- uses: pnpm/action-setup@v4
39+
name: Install pnpm
40+
with:
41+
run_install: false
42+
43+
- uses: actions/setup-node@v4
44+
with:
45+
node-version: "22"
46+
cache: "pnpm"
47+
48+
- name: Install dependencies
49+
run: |
50+
pnpm install --frozen-lockfile
51+
52+
- name: Install Playwright Browsers
53+
run: |
54+
pnpm exec playwright install --with-deps
55+
56+
- name: Run e2e server
57+
working-directory: ./e2e/server
58+
run: |
59+
docker compose up -d
60+
61+
- name: Waiting dashboard service to be healthy
62+
working-directory: ./e2e/server
63+
run: |
64+
E2E_SERVER="dashboard-e2e"
65+
TIMEOUT=30
66+
timeout $TIMEOUT bash -c '
67+
until [ "$(docker inspect --format="{{.State.Health.Status}}" $(docker compose ps -q '$E2E_SERVER'))" = "healthy" ]; do
68+
echo "'$E2E_SERVER' is starting..."
69+
sleep 5
70+
done
71+
' || (echo "$E2E_SERVER not healthy after $TIMEOUT seconds" && exit 1)
72+
73+
- name: Run e2e tests
74+
run: |
75+
pnpm e2e
76+
77+
- uses: actions/upload-artifact@v4
78+
if: ${{ !cancelled() }}
79+
with:
80+
name: test-results
81+
path: apps/site-e2e/test-results/
82+
retention-days: 7
83+
84+
- uses: actions/upload-artifact@v4
85+
if: ${{ !cancelled() }}
86+
with:
87+
name: playwright-report
88+
path: playwright-report/
89+
retention-days: 7
90+
91+
- name: Print Components Logs
92+
if: failure()
93+
run: |
94+
docker ps --format '{{.Names}}' | xargs -I{} bash -c "echo ================= {} ==================== && docker logs {} && echo ================= {} ===================="

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ dist-ssr
2424
*.sw?
2525

2626
/.pnpm-store
27+
28+
# Playwright
29+
/test-results/
30+
/playwright-report/
31+
/blob-report/
32+
/playwright/.cache/
33+
34+
.eslintcache

e2e/auth.spec.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { expect } from '@playwright/test';
19+
import { test } from '@utils/test';
20+
21+
import { getAPISIXConf } from './utils/common';
22+
23+
// use empty storage state to avoid auth
24+
test.use({ storageState: { cookies: [], origins: [] } });
25+
26+
test('can auth with admin key', { tag: '@auth' }, async ({ page }) => {
27+
const settingsModal = page.getByRole('dialog', { name: 'Settings' });
28+
const adminKeyInput = page.getByRole('textbox', { name: 'Admin Key' });
29+
const failedMsg = page.getByText('failed to check token');
30+
31+
const checkSettingsModal = async () => {
32+
await expect(failedMsg).toBeVisible();
33+
await expect(settingsModal).toBeVisible();
34+
await expect(page.getByText('UI Commit SHA')).toBeVisible();
35+
};
36+
37+
await test.step('fill wrong admin key, settings modal always be visible', async () => {
38+
await checkSettingsModal();
39+
40+
await expect(adminKeyInput).toBeEmpty();
41+
await adminKeyInput.fill('wrong-admin-key');
42+
await page
43+
.getByRole('dialog', { name: 'Settings' })
44+
.getByRole('button')
45+
.click();
46+
47+
await page.reload();
48+
await expect(failedMsg).toBeVisible();
49+
await expect(settingsModal).toBeVisible();
50+
});
51+
52+
await test.step('fill correct admin key, settings modal can be hidden', async () => {
53+
await page.reload();
54+
await checkSettingsModal();
55+
56+
const { adminKey } = await getAPISIXConf();
57+
await adminKeyInput.clear();
58+
await adminKeyInput.fill(adminKey);
59+
await page
60+
.getByRole('dialog', { name: 'Settings' })
61+
.getByRole('button')
62+
.click();
63+
64+
await page.reload();
65+
await expect(failedMsg).toBeHidden();
66+
});
67+
});

e2e/server/Dockerfile

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
FROM node:22-alpine AS base
19+
20+
# install deps
21+
FROM base AS deps
22+
WORKDIR /app
23+
COPY package.json pnpm-lock.yaml* ./
24+
RUN \
25+
if [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm install; \
26+
else echo 'Lockfile not found.' && exit 1; \
27+
fi
28+
29+
# build ui
30+
FROM base AS builder
31+
WORKDIR /app
32+
COPY --from=deps /app/node_modules ./node_modules
33+
COPY . .
34+
# we need git to get commit sha
35+
RUN apk add --no-cache git
36+
RUN corepack enable pnpm && pnpm build
37+
38+
# serve ui
39+
FROM nginx:1.28.0-alpine-slim AS runner
40+
COPY --from=builder /app/dist /usr/share/nginx/html
File renamed without changes.

e2e/server/docker-compose.common.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
services:
19+
apisix:
20+
image: 'apache/apisix:3.12.0-debian'
21+
restart: always
22+
volumes:
23+
- ./apisix_conf.yml:/usr/local/apisix/conf/config.yaml:ro
24+
depends_on:
25+
- etcd
26+
networks:
27+
- apisix
28+
29+
etcd:
30+
image: bitnami/etcd:3.5
31+
restart: always
32+
volumes:
33+
- etcd_data:/bitnami/etcd
34+
environment:
35+
ETCD_ENABLE_V2: 'true'
36+
ALLOW_NONE_AUTHENTICATION: 'yes'
37+
ETCD_ADVERTISE_CLIENT_URLS: 'http://etcd:2379'
38+
ETCD_LISTEN_CLIENT_URLS: 'http://0.0.0.0:2379'
39+
networks:
40+
- apisix
41+
42+
networks:
43+
apisix:
44+
driver: bridge
45+
46+
volumes:
47+
etcd_data:

e2e/server/docker-compose.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
include:
19+
- docker-compose.common.yml
20+
services:
21+
dashboard-e2e:
22+
build:
23+
context: ../..
24+
dockerfile: e2e/server/Dockerfile
25+
volumes:
26+
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
27+
networks:
28+
- apisix
29+
ports:
30+
- '6174:6174'
31+
depends_on:
32+
- apisix
33+
healthcheck:
34+
test:
35+
[
36+
'CMD',
37+
'wget',
38+
'--quiet',
39+
'--tries=1',
40+
'--spider',
41+
'http://127.0.0.1:6174/ui/',
42+
]
43+
interval: 10s
44+
timeout: 5s
45+
retries: 5
46+
start_period: 10s

0 commit comments

Comments
 (0)