Skip to content

Commit 526d46d

Browse files
authored
test: upstream list pages (#3056)
1 parent 665ad24 commit 526d46d

File tree

17 files changed

+680
-104
lines changed

17 files changed

+680
-104
lines changed

e2e/pom/upstreams.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
import { uiGoto } from '@e2e/utils/ui';
18+
import { expect, type Page } from '@playwright/test';
19+
20+
const locator = {
21+
getUpstreamNavBtn: (page: Page) =>
22+
page.getByRole('link', { name: 'Upstreams' }),
23+
getAddUpstreamBtn: (page: Page) =>
24+
page.getByRole('button', { name: 'Add Upstream' }),
25+
};
26+
27+
const assert = {
28+
isIndexPage: async (page: Page) => {
29+
await expect(page).toHaveURL((url) => url.pathname.endsWith('/upstreams'));
30+
const title = page.getByRole('heading', { name: 'Upstreams' });
31+
await expect(title).toBeVisible();
32+
},
33+
isAddPage: async (page: Page) => {
34+
await expect(page).toHaveURL((url) =>
35+
url.pathname.endsWith('/upstreams/add')
36+
);
37+
const title = page.getByRole('heading', { name: 'Add Upstream' });
38+
await expect(title).toBeVisible();
39+
},
40+
};
41+
42+
const goto = {
43+
toIndex: (page: Page) => uiGoto(page, '/upstreams'),
44+
toAdd: (page: Page) => uiGoto(page, '/upstreams/add'),
45+
};
46+
47+
export const upstreamsPom = {
48+
...locator,
49+
...assert,
50+
...goto,
51+
};

e2e/tests/upstreams.list.spec.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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 { upstreamsPom } from '@e2e/pom/upstreams';
19+
import { setupPaginationTests } from '@e2e/utils/pagination-test-helper';
20+
import { e2eReq } from '@e2e/utils/req';
21+
import { test } from '@e2e/utils/test';
22+
import { expect, type Page } from '@playwright/test';
23+
24+
import { deleteAllUpstreams, putUpstreamReq } from '@/apis/upstreams';
25+
import { API_UPSTREAMS } from '@/config/constant';
26+
import type { APISIXType } from '@/types/schema/apisix';
27+
28+
test('should navigate to upstreams page', async ({ page }) => {
29+
await test.step('navigate to upstreams page', async () => {
30+
await upstreamsPom.getUpstreamNavBtn(page).click();
31+
await upstreamsPom.isIndexPage(page);
32+
});
33+
34+
await test.step('verify upstreams page components', async () => {
35+
await expect(upstreamsPom.getAddUpstreamBtn(page)).toBeVisible();
36+
37+
// list table exists
38+
const table = page.getByRole('table');
39+
await expect(table).toBeVisible();
40+
await expect(table.getByText('ID', { exact: true })).toBeVisible();
41+
await expect(table.getByText('Name', { exact: true })).toBeVisible();
42+
await expect(table.getByText('Labels', { exact: true })).toBeVisible();
43+
await expect(table.getByText('Actions', { exact: true })).toBeVisible();
44+
});
45+
});
46+
47+
const upstreams: APISIXType['Upstream'][] = Array.from(
48+
{ length: 11 },
49+
(_, i) => ({
50+
id: `upstream_id_${i + 1}`,
51+
name: `upstream_name_${i + 1}`,
52+
nodes: [
53+
{
54+
host: `node_${i + 1}`,
55+
port: 80,
56+
weight: 100,
57+
},
58+
],
59+
})
60+
);
61+
62+
test.describe('page and page_size should work correctly', () => {
63+
test.describe.configure({ mode: 'serial' });
64+
test.beforeAll(async () => {
65+
await deleteAllUpstreams(e2eReq);
66+
await Promise.all(upstreams.map((d) => putUpstreamReq(e2eReq, d)));
67+
});
68+
69+
test.afterAll(async () => {
70+
await Promise.all(
71+
upstreams.map((d) => e2eReq.delete(`${API_UPSTREAMS}/${d.id}`))
72+
);
73+
});
74+
75+
// Setup pagination tests with upstream-specific configurations
76+
const filterItemsNotInPage = async (page: Page) => {
77+
// filter the item which not in the current page
78+
// it should be random, so we need get all items in the table
79+
const itemsInPage = await page
80+
.getByRole('cell', { name: /upstream_name_/ })
81+
.all();
82+
const names = await Promise.all(itemsInPage.map((v) => v.textContent()));
83+
return upstreams.filter((d) => !names.includes(d.name));
84+
};
85+
86+
setupPaginationTests(test, {
87+
pom: upstreamsPom,
88+
items: upstreams,
89+
filterItemsNotInPage,
90+
getCell: (page, item) =>
91+
page.getByRole('cell', { name: item.name }).first(),
92+
});
93+
});
94+

e2e/utils/common.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
import { readFile } from 'node:fs/promises';
17+
import { access, readFile } from 'node:fs/promises';
1818
import path from 'node:path';
1919

20+
import { nanoid } from 'nanoid';
2021
import { parse } from 'yaml';
2122

2223
type APISIXConf = {
@@ -29,3 +30,14 @@ export const getAPISIXConf = async () => {
2930
const res = parse(file) as APISIXConf;
3031
return { adminKey: res.deployment.admin.admin_key[0].key };
3132
};
33+
34+
export const fileExists = async (filePath: string) => {
35+
try {
36+
await access(filePath);
37+
return true;
38+
} catch {
39+
return false;
40+
}
41+
};
42+
43+
export const randomId = (info: string) => `${info}_${nanoid()}`;

0 commit comments

Comments
 (0)