diff --git a/e2e/tests/regression/plugin.docs-link.spec.ts b/e2e/tests/regression/plugin.docs-link.spec.ts new file mode 100644 index 0000000000..6c5977dba9 --- /dev/null +++ b/e2e/tests/regression/plugin.docs-link.spec.ts @@ -0,0 +1,137 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { routesPom } from '@e2e/pom/routes'; +import { e2eReq } from '@e2e/utils/req'; +import { test } from '@e2e/utils/test'; +import { expect } from '@playwright/test'; + +import { deleteAllRoutes } from '@/apis/routes'; + +// #3461: the plugin editor never said what a plugin does. The gateway +// carries no description for any plugin (0 of 106 have a +// `schema.description`), so the docs site is the only source, and its URL +// is derivable from the plugin name. + +const DOCS = 'https://apisix.apache.org'; + +test.beforeAll(async () => { + await deleteAllRoutes(e2eReq); +}); + +test.afterEach(async ({ page }) => { + await page + .evaluate(() => localStorage.removeItem('settings:lang')) + .catch(() => {}); +}); + +test.afterAll(async () => { + await deleteAllRoutes(e2eReq); +}); + +const openPicker = async (page: import('@playwright/test').Page) => { + await routesPom.toAdd(page); + await routesPom.isAddPage(page); + await page.getByRole('button', { name: 'Select Plugins' }).click(); + const picker = page.getByRole('dialog', { name: 'Select Plugins' }); + await expect(picker).toBeVisible(); + return picker; +}; + +const openPluginDrawer = async ( + page: import('@playwright/test').Page, + plugin: string +) => { + const picker = await openPicker(page); + await picker.getByPlaceholder('Search').fill(plugin); + await picker + .getByTestId(`plugin-${plugin}`) + .getByRole('button', { name: 'Add' }) + .click(); + const drawer = page.getByRole('dialog', { name: 'Add Plugin' }); + await expect(drawer).toBeVisible(); + return drawer; +}; + +test('the plugin editor links that plugin documentation', async ({ page }) => { + const drawer = await openPluginDrawer(page, 'key-auth'); + + // getByRole('link') is the load-bearing part: it fails if the control + // ever becomes a