Files
threshold-ui/e2e-tests/admin/tests/pagination.spec.js
T
hashiccandZhihe Li b42ecbff36 Add api client for playwright e2e tests (#2901)
* chore: 🤖 add @openapitools/openapi-generator-cli

* chore: 🤖 Add @nestjs/core and @openapitools/openapi-generator-cli to ignoredBuiltDependencies

These packages use postinstall for a opencollective notice

* chore: 🤖 add package.json scripts for open-api client gen

* chore: 🤖 add openapi generated files

* chore: 🤖 add boundary api client fixture

* chore: 🤖 incorporate api client fixture with base fixture

* chore: 🤖 migrate existing test to use boundary api fixture

* refactor: 💡 remove org cleanup from test

* refactor: 💡 update sorting e2e test to use api client

* refactor: 💡 clean up api client resource clean up logging

* docs: ✏️ update jsdoc links for domain clients

* chore: 🤖 avoid adding copywright headers to generated api

* Add missing copyright headers

* chore: 🤖 remove fetch argument from api client class

The hope was to use request.fetch but playwright's fetch is a
non-standard fetch which causes the generated api client to fail when
using .clone() on the response

* chore: 🤖 add optional OPENAPI_SWAGGER_URL_OR_FILE for openapi-client
generation

The OPENAPI_SWAGGER_URL_OR_FILE env var can be used to specify the
-i flag the generate:api-client script with either:
* a relative path
* an absolute path
* a url like: https://raw.githubusercontent.com/hashicorp/boundary/refs/heads/main/internal/gen/controller.swagger.json

* refactor: 💡 clean up and refactor boundary-api-client fixture

* chore: 🤖 add extra doc links and delete methods

* test: 💍 add test to ensure that api-client fixture works

* test: 💍 update existing e2e test examples with api-client

* docs: ✏️ add comment for api-client e2e test

* docs: ✏️ add additional links to service docs for api clients

* refactor: 💡 cleanup api-client and corresponding test

* docs: ✏️ add api client fixture docs to e2e README

* fix: 🐛 fix regex

* remove unnecessary capture group
* add "-" to regex to allow for url segments like "storage-buckets" in
  "/v1/storage-buckets"

* docs: ✏️ comment potential edge case in e2e api client cleanup

* docs: ✏️ fix comment typo

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

* docs: ✏️ remove auth flag for generating e2e client

* docs: ✏️ add mention that java is required for generate:api

* chore: 🤖 implement pr feedback

* chore: 🤖 Clean up api client and add more extensive test

* chore: 🤖 fix casing in api-client test

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2025-08-12 18:08:35 -04:00

171 lines
5.4 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { test } from '../../global-setup.js';
import { expect } from '@playwright/test';
import { nanoid } from 'nanoid';
test(
'Search and Pagination (Targets)',
{ tag: ['@ce', '@ent', '@aws', '@docker'] },
async ({ page, apiClient }) => {
const org = await apiClient.clients.Scope.scopeServiceCreateScope({
item: {
name: `Org-${nanoid()}`,
scopeId: 'global',
},
});
const project = await apiClient.clients.Scope.scopeServiceCreateScope({
item: {
name: `Project-${nanoid()}`,
scopeId: org.id,
},
});
// Create targets
let targets = [];
const targetCount = 15;
for (let i = 0; i < targetCount; i++) {
const target = await apiClient.clients.Target.targetServiceCreateTarget({
item: {
name: `Target-${nanoid()}`,
scopeId: project.id,
type: 'tcp',
attributes: {
default_port: 22,
},
},
});
targets.push(target);
}
// Navigate to targets page
await page.goto('/');
await page.getByRole('link', { name: org.name }).click();
await page.getByRole('link', { name: project.name }).click();
await page
.getByRole('navigation', { name: 'Application local navigation' })
.getByRole('link', { name: 'Targets' })
.click();
await expect(page.getByRole('heading', { name: 'Targets' })).toBeVisible();
// Check pagination
// The most recent target should be visible. The oldest target should not be
// visible since there are 15 targets and the default page size is 10.
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeHidden();
// Navigate to the second page. The oldest target should now be visible.
await page
.getByRole('navigation', { name: 'pagination' })
.getByRole('link', { name: 'page 2' })
.click();
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeHidden();
// Use the "previous page" button to navigate back to the first page.
await page
.getByRole('navigation', { name: 'pagination' })
.getByRole('link', { name: 'Previous page' })
.click();
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeHidden();
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeVisible();
// Use the "next page" button to navigate back to the second page.
await page
.getByRole('navigation', { name: 'pagination' })
.getByRole('link', { name: 'Next page' })
.click();
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeHidden();
// Use the search box to find the most recent target.
await page
.getByRole('searchbox', { name: 'Search' })
.fill(targets[targets.length - 1].name);
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeHidden();
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 2].name }),
).toBeHidden();
// Clear the search box
await page.getByRole('searchbox', { name: 'Search' }).clear();
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeHidden();
await expect(
page.getByRole('link', { name: targets[targets.length - 2].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeVisible();
// Use the "Items per page" options to show 30 items per page.
await page
.getByRole('combobox', { name: 'Items per page' })
.selectOption('30');
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 2].name }),
).toBeVisible();
// Use the "Items per page" options to show 50 items per page.
await page
.getByRole('combobox', { name: 'Items per page' })
.selectOption('50');
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 2].name }),
).toBeVisible();
// Use the "Items per page" options to show 10 items per page.
await page
.getByRole('combobox', { name: 'Items per page' })
.selectOption('10');
await expect(
page.getByRole('link', { name: targets[0].name }),
).toBeHidden();
await expect(
page.getByRole('link', { name: targets[targets.length - 2].name }),
).toBeVisible();
await expect(
page.getByRole('link', { name: targets[targets.length - 1].name }),
).toBeVisible();
},
);