Skip to main content
Version: 2026.1.12

End-to-end tests

Introduction to end-to-end tests

End-to-end (E2E) testing helps you verify the complete flow of an application from the perspective of your users. It complements other quality measures such as branching and merging, code reviews, unit tests, smoke tests, and validations by providing confidence that the system works as intended in real-world scenarios. Where unit and integration tests focus on smaller components, end-to-end tests confirm that these components work together correctly.

Testwise for end-to-end testing

Applications built with the Thinkwise Platform are often complex and remain in use for many years. To ensure quality, test automation is essential. It provides consistent and repeatable checks and reduces the need for manual regression testing, so testers can focus on new features and critical areas. We recommend to automate tests for stable, user-accepted functionality and perform the tests with test accounts that represent actual Role & User Group rights.

Testwise is a test automation solution designed specifically for Thinkwise applications in the Universal UI. Built on Playwright, it adds prebuilt page extensions, custom controls, and components that follow Thinkwise UI patterns. With these, you can easily interact with complex screens such as grids, forms, and action bars. Testwise also includes scripts for authentication and user simulation, helping you avoid repetitive setup tasks and improving test stability.

In summary, Testwise streamlines end-to-end testing by turning common Thinkwise actions into clear, reusable methods. This allows development teams to focus on validating business logic.

note

Testwise is designed for applications using the Universal UI. If you have applications that use a different UI, such as the Windows GUI, we suggest migrating to the Universal UI to benefit from Testwise and other modern features. For more information, see Transition to the Universal UI.

Benefits of Testwise

Using Testwise as part of your Software Factory application testing and automation efforts offers several benefits:

  • You do not have to maintain components yourself. If the Universal UI changes, Thinkwise maintains and update component logic in Testwise.
  • Test development is faster with built-in, ready to use functions and helpers that you can use directly.
  • The Thinkwise Application model is synced to your Testwise project and for all Subject <> Screen Type combinations Subject page objects are automatically created in the Testwise repository.

One limitation of Testwise is the learning curve. This is because Testwise is a technology-specific automation library, so it takes time and effort to become familiar with its features.

Set up Testwise

Prerequisites

  1. Install Visual Studio Code (Windows, macOS, or Linux).
  2. Open Visual Studio Code (VSCode) and go to extensions.
  3. Search Playwright Test for VSCode and install the extension.
  4. Install Node.js.
  5. Create a folder in your file explorer and open it. This folder will be the folder for your test project.
  6. Press Alt + D to select the address bar.
  7. Type cmd and press Enter to open the terminal.
  8. In the terminal type code . and press Enter to open VSCode.
  9. In VSCode press Ctrl+~ to open up the terminal within VSCode.

Set up project dependencies

  1. To create a new NPM project run the following command:

    npm init
    • Press Enter until you see the following line in the terminal: type: (commonjs).
    • Enter module and press Enter.
    • A confirmation message will pop-up, press Enter again.
  2. To install Testwise, run:

    npm i @thinkwise/testwise
  3. Open the testwise.json file.

  4. Replace the example values inside environmentSettings with valid details:

    {
    "environmentSettings": {
    "baseUrl": "https://<your-environment>",
    "serviceUrl": "https://<your-environment>/indicium",
    "metaEndpoint": "iam",
    "authUser": "<username>",
    "authUserPassword": "<password>",
    "guiApplAlias": "<application-alias>"
    }
    }
    note
    • Use a test user instead of personal login details.
    • The baseUrl should match your Universal login page.
    • The serviceUrl should match the Meta server URL up until indicium.

Initialize Playwright

To initialize Playwright, run:

npm init playwright
  1. The message 'Where to put your end-to-end tests?' is shown on the screen. To continue, press Enter.
  2. The message 'Add a GitHub Actions workflow? is shown on the screen. To continue, press N to select No.
  3. The message 'Install Playwright browsers (can be done manually via 'npx playwright install'? is shown on the screen. To continue, press Enter.
  4. Open the file playwright.config.ts, then change // baseURL: 'http://localhost:3000', to baseURL: `${testwiseConfig().get<string>('environmentSettings.baseUrl')}`,​​​
  5. Select the testWiseConfig part of the baseURL and press Ctrl+..
  6. Select Add import from "@thinkwise/testwise" as import option. The import will be added at the top of your code.
  7. Save your changes, by pressing Ctrl+S.

Sync the application model to Testwise

Synchronizing the application model to Testwise will generate Subject page objects. You can directly import and use these in your tests or extend in your own pages, in addition to all Thinkwise components.

To sync the application model, run:

 npx testwise sync
note

Repeat this step whenever the Thinkwise Application model is updated on the test environment.

The following phases take place:

 Phase 1: Cleanup and Initial Compilation
Phase 2: Build Model Data
Phase 3: Refine Model Data
Phase 4: Generate Artifacts
Phase 5: Final Compilation
Phase 6: Backup

The end of the sync is clearly indicated:

 Sync process completed successfully!
note

In model synchronization:

  • Page objects will be generated for the subjects the authUser is authorized for in IAM. This can take a couple of minutes depending on your application size.
  • If your testwise.json configuration is already in place before installing this version, the model and artifacts are generated automatically during installation.
  • If you install first and add/update configuration afterwards, you will need to run the sync command above to retrieve all updates.

Introducing Generated Artifacts

The sync step resulted in auto-generated page objects in Testwise. You can directly import and use these page objects in your tests or extend in your own pages. The page objects are essentially a combination of a Subject and Screen type as configured in the Software Factory. Use these to ensure your test scripts are simpler, shorter, and less maintenance-prone in the future. You can find an example below to help you get started.

Naming convention

There are several naming conventions:

  • Subject name is converted from snake case to Pascal case
  • Screen type is one of:
    • Main
    • Detail
    • Popup
    • Zoom

Examples:

Model subjectVariantScreenGenerated name
category-MainCategoryMain
category-DetailCategoryDetail
categoryAdminMainCategoryAdminMain

Create your first test

To create a linear test script from a record with playback functionality in Playwright:

  1. In VSCode, go to the tab Testing and select Record new. This open a new browser to start recording your actions.
  2. Go to your application.
  3. Log in and perform the actions for your test case.
  4. Close the browser to stop the recording.

Example: linear script with record and playback function

import { test, expect } from '@playwright/test';

test.describe('Sample Test Suite', () => {
test('Add time entry', async ({ page }) => {
await page.goto('https://tcp.thinkwise.app/universal/#application=tcp');
await page.getByTestId('login__username__input').click();
await page.getByTestId('login__username__input').fill('testUser');
await page.getByTestId('login__password__input').click();
await page.getByTestId('login__password__input').fill('Xyz@245');
await page.getByTestId('login__login-button').click();
await page.getByTestId('listbar__project-beheer').click();
await page.getByTestId('listbar__project-beheer__item__0').click();
await page.getByTestId('actionbar__add').click();
await page.getByTestId('form-field__project-id__control__input').click();
await page.getByTestId('form-field__project-id__control__input').fill('q');
await page.getByTestId('form-field__project-id__control__option__quality-assurance').click();
await page.getByTestId('form-field__sub-project-id__control__input').click();
await page.getByTestId('form-field__sub-project-id__control__option__automated-testing').click();
await page.getByTestId('form-field__aantal-uren__input').click();
await page.getByTestId('form-field__aantal-uren__input').fill('1');
await page.getByTestId('form-field__activiteit-id__control__input').click();
await page.getByTestId('form-field__activiteit-id__control__input').fill('Build example test');
await page.getByTestId('form-field__omschrijving__input').click();
await page.getByTestId('form-field__omschrijving__input').fill('This is my description');
await page.getByTestId('form-field__adres-id__control__input').click();
await page.getByTestId('form-field__adres-id__control__input').fill('Test Street');
await page.getByTestId('actionbar__save').click();
expect(await page.getByTestId('screen__uren-boeken-dag__grid1').getByRole('row').all).toEqual(1);
});
});

Convert the script with Testwise

Apply common test automation patterns in the optimized script. For example, the AAA pattern and Page Object Model (POM) pattern. This approach maximizes reusability and minimizes maintenance by reducing repeating logic.

Testwise has functionality to replace and convert steps in the recording. To be able to use this functionality you need to import the test fixture from Testwise.

To import the test fixture, follow these steps:

  1. Change the import on line 1 to:

    import { expect } from '@playwright/test';
  2. Add a new import:

    import { test } from '@thinkwise/testwise';
  3. Remove all steps part of the login process where the test id starts with login and replace with:

    await page.logInWithCredentials('username', 'password');
  4. In Testwise, screens are exposed as typed subjects on page.subject. Introduce the subject once:

    const event = await page.subject.EventMain;
  5. Replace page.getByTestId with the Subject structure:

    Playwright (old)Testwise (new)
    page.getByTestId('actionbar__add')event.toolbarXXXX.getAddButton()
    page.getByTestId('form-field__x__input')event.form1.getFieldByColId('x')
    lookup option clickevent.form1.<lookup_name>.lookupSelect('value')
    grid selectorevent.grid1
  6. Refactor to act as components, not selectors:

    Instead of:

    await page.getByTestId('form-field__event-name__input').fill('1');

    You always convert to:

    await event.form1.getFieldByColId('event-name').fill('1');
  7. Go back to the Testing tab in VSCode.

  8. Run your test again by selecting the test case and selecting Run test. If your test passes, you are successfully linked to the Testwise library.

Example: optimized script

import { expect } from '@playwright/test';
import { test } from '@thinkwise/testwise';

test.describe('Sample Test Suite', () => {
test('Add time entry', async ({ page }) => {

//Arrange
const event = await page.subject.EventMain;
await page.logInWithCredentials('testUser', 'Xyz@245');
await page.goToDeepLink('subject=event');

// Act
await event.toolbar503DB1BD.getAddButton().click();
await event.form1.getFieldByColId('event-name').fill('A random event');
await event.form1.getFieldByColId('event-date').fill('10/10/2027');
await event.form1.categoryIdDropdown.lookupSelect('Internal');
await event.form1.LocationtIdDropdown.lookupSelect('DE');
await event.toolbar503DB1BD.getSaveButton().click();

// Assert
await expect(event.grid2.verifyNumberOfRecordsInGrid(1)).resolves.not.toThrow();
});
});

Scripts

To log in via the terminal and run a test:

npx testwise-credentials <script_name_to_run_tests>

An example of test scripts for the testwise-credentials command:

"scripts": {
"test": "npx playwright test --ui --reporter=html --output=./playwright-report",
"debug": "npx playwright test --debug --reporter=html --output=./playwright-report",
"headless": "npx playwright test --reporter=html --output=./playwright-report"
}

Page extensions for Playwright

In this section, you can find commonly used functionalities that are built into the Playwright page object.

Deep linking

Deep linking allows you to bypass UI navigation. The goToDeepLink() navigates within the current application, utilizing the configured baseUrl, to allow environment switching without tests breaking. Examples how to use this functionality are provided.

  • To navigate to: https://tcp.thinkwise.app/universal/#application=tcp/subject=tms_ticket

     await page.goToDeepLink('subject=tms_ticket');
  • To navigate to: https://tcp.thinkwise.app/universal/#application=tcp/subject=vw_persoon_capaciteit/subjectVariant=vw_persoon_capaciteit_medewerker_planning

    await page.goToDeepLink('subject=vw_persoon_capaciteit/subjectVariant=vw_persoon_capaciteit_medewerker_planning');

The deep-link format for the Universal GUI is: https://[server]/#application=[alias]/processflow=[id]?.... The helper behind the goToDeepLink() method works with this format and automatically prefixes the configured baseURL, making tests portable across environments. For more details on the URL structure, see Create a deep link for Universal GUI.

Authentication

The login method uses environment variables. The following script sets process environment variables to use with this method.

When you run the testwise-credentials script, executed tests use the specified credentials provided at runtime. This uses the specified credentials on any tests where the await page.logIn() extension method is invoked.

  • logInWithCredentials() - To log in using test credentials, a username and password.

    import { test } from '@thinkwise/testwise';

    test.describe('Log in with credentials', () => {
    test.beforeEach(async ({ page }) => {
    await page.logInWithCredentials('MyUsername', 'MyPassword');
    });

    test('should display the main menu after login', async ({ page }) => {
    // Add your test steps here
    });
    });
  • logInWithOptions() - Used to pass additional information, such as a different application to launch into. See Enumerations for more options.

    import { test, type UniversalLoginOptions } from '@thinkwise/testwise';

    test.describe('Log in with options', () => {
    test.beforeEach(async ({ page }) => {
    const options: UniversalLoginOptions = {
    username: 'MyUsername',
    password: 'MyPassword',
    config: {
    defaultApplication: 'iam'
    }
    };

    await page.logInWithOptions(options);
    });

    test('should display the main menu after login', async ({ page }) => {
    // Add your test steps here
    });
    });
  • logOut() - Used to log out in scenarios where logging out is required.

    import { test } from '@thinkwise/testwise';

    test.describe('Test logout functionality', () => {
    test.beforeEach(async ({ page }) => {
    await page.logInWithCredentials('MyUsername', 'MyPassword');
    });

    test('should log me out successfully', async ({ page }) => {
    await page.logOut();
    // Add your verification steps here
    });
    });

User simulation

note

You need to be logged in as a user with simulation rights for this functionality to work. See User simulation for more information.

There are multiple ways to start or stop a user simulation:

  • simulateUser() - To simulate other users after logging in.

    test('should be able to simulate a different user and do stuff', async ({ page }) => {
    await page.simulateUser('UsernameOfSimulatedUser');

    // Do something as that user
    });
  • getSimulatedUser() - Get the username of the currently simulated user.

    test('should be able to get simulated users username', async ({ page }) => {
    const simulatedUser = await page.getSimulatedUser();

    console.log(`Simulated user is: ${simulatedUser}`);
    });
  • stopSimulation() - Stop user simulation.

    test('should be able to do other stuff after stopping user simulation', async ({ page }) => {
    await page.simulateUser('UsernameOfSimulatedUser');

    // Do something as simulated user

    await page.stopSimulation();

    // Do some other stuff as logged in user
    });

Components

Components are the centralized logic that serve as counterparts to components in the Software Factory. They provide access to specific actions that make end-user interaction easier.

In Testwise there are mainly two types of components:

  • Screen Components - A collection of components defined in your Screen Types within Software Factory.
  • Global Components - Generally static components such the Top-bar, or floating components such as Pop-ups; basically anything that is not a screen component

For more information on the available screen components, see Universal screen components and Screen components.

Screen Components

Tab

Tabs represent tab strips in Thinkwise screens (for example, List tabs, Forms or Detail tabs). They allow navigation between sections within a subject or screen type.

In model-generated tests, the Component Tabs container on a subject is exposed on the tab as tab.

Hierarchy Generated component tabs follow the subject structure:

  <subject><tab><tabaction>

Available methods for the Component tab:

  • Open the List tab (defaults to tabindex = -1 for master): openListTab(tabindex?: string): Promise<void>
openListTab(tabindex?: string): Promise<void>
  • Get the locator for the List tab: getListTab(tabindex?: string): Locator
await event.tab.getListTab().click();
  • Open the Form tab: openFormTab(): Promise<void>
await event.tab.openFormTab();
  • Get the locator for the Form tab: getFormTab(): Locator
await event.tab.getFormTab().click();
  • Open a tab by its id (data-testid suffix): openTabById(tabId: string): Promise<void>
await componentTab.openById('users');
  • Open a tab by index:
await componentTab.openByIndex(2);
  • Get the badge count for a tab:
await event.tab.openByIndex(0);

const badge = await event.tab.getBadgeCount('user-group-tags');

Returns 0 if no badge is visible.

Action bar

In model-generated tests, the Action Bar is automatically available through the generated subject structure. It is exposed as part of the tab hierarchy and provides strongly typed access to all standard Thinkwise action bar buttons.

No manual initialization or context configuration are required.

Usage

The action bar is accessed through the generated subject model:

await <yoursubjecthere>.<yourToolbarIdhere>.getUpdateButton().click();

Example

const event = await page.subject.EventMain;

await event.toolbar3574C040.getUpdateButton().click();

Hierarchy

Generated action bars follow the subject structure:

  <subject><toolbar>

Where:

  • <subject> represents the generated subject object

  • <toolbar> is the generated toolbar identifier

    Each toolbar exposes the standard Thinkwise action bar methods.

Accessing Buttons

Buttons are retrieved using dedicated getter methods. You can perform any Playwright action on the returned element. For buttons in the overflow menu, you need to include .overflowMenu to call them.

Example

  await event.toolbar3574C040.getAddButton().click();
await event.toolbar3574C040.getDeleteButton().click();
await event.toolbar3574C040.getRefreshButton().click();
await event.toolbar3574C040.overflowMenu.getExportButton().click();

Available Methods

The generated Action Bar provides access to all standard buttons, including:

  • getAddButton
  • getCancelButton
  • getCopyButton
  • getDeleteButton
  • getRefreshButton
  • getSaveButton
  • getUpdateButton
  • getExportButton
  • getImportButton
  • getExportImmediatelyButton
  • getMassUpdateButton
  • getQuickFilterButton
  • getFilterButton
  • getClearAllFiltersButton
  • getRestoreSortOrderButton
  • getSortButton
  • getSearchInput
  • getUpScreenTypeButton
  • getUpDetailSettingsButton
  • getUpManagePrefiltersButton
  • getUpGridSettingsButton
  • getCubeSortButton
  • getCubePivotSettingsButton
  • getCubeChartSettingsButton
  • getSaveAsCubeViewButton
  • getDeleteCubeViewButton
  • getCollapseAllButton
  • getExpandAllButton

Each method returns a Playwright locator, allowing standard interactions such as:

await event.toolbar3574C040.getSaveButton().click();
await expect(event.toolbar3574C040.getDeleteButton()).toBeVisible();

Form

In model-generated tests, each form is exposed directly on the generated subject (per tab), and can be used either via generated fields (preferred) or via the Form component API for generic interactions.

Thinkwise documents the Form Testwise component and shows usage such as retrieving fields by column id and checking edit mode.

Usage of generated form fields

Generated inputs are available as strongly typed properties on the form:

await <yoursubjecthere>.<yourScreenComponentIdHere>.<yourColumnNamehere>.fill('Your value to fill here');

Example

const event = await page.subject.EventMain;

await event.form2.eventNameField.fill('Test Event');

Usage of Form component methods

The form instance itself is also available from the generated subject:

await <yoursubjecthere>.<yourScreenComponentIdHere>.isInEditMode();
await <yoursubjecthere>.<yourScreenComponentIdHere>.getFieldByColId('col-id__control').fill('Your value to fill here');

Example

const event = await page.subject.EventMain;

await event.form2.isInEditMode();
await event.form2.getFieldByColId('event-name__control').fill('Test Event');

The form instance itself is also available from the generated subject:

Available Methods for the Form component:

  • Verify edit mode: isInEditMode(): Promise<boolean>
const editing = await event.form2.isInEditMode();

// Assert
expect(isInEditMode).toBeTruthy();
  • Get field by current value: getFieldByValue(value: string): Locator
await event.form2.getFieldByValue('Internal').click();
  • Get field by column ID: getFieldByColId(colId: string): Locator
await event.form2.getFieldByColId('event-name__control').fill('Test Event');
  • Get lookup button by column ID: clickInFieldLookup(colId: string): Promise<void>
await event.form2.clickInFieldLookup('category-id__control');

Grid

Access the grid through the generated subject model:

Example

const event = await page.subject.EventMain;

await event.grid1.getCellByExactValue('EVT-2024-Q1-Jan').click();

Hierarchy

Generated grids follow the subject structure:

<subject><grid><action> 

Example

await event.grid1.getRowByIndex(0).click();

Column Cell Collections

In addition to the generic grid methods, model generation can expose typed column cell collections (as Promise<Locator[]>) for direct access to all visible cells in a column.

Example

const nameCells = await event.grid1.eventNameColumnCells;

Available Methods

Navigation and Selection

  • getColumnHeaderByText(text: string): Locator
  • getRowByIndex(rowIndex: number): Locator
  • getRowByRowId(rowIdPattern: string): Locator
  • getCellByExactValue(value: string): Locator
  • rows(): Locator
  • selectRowByRowId(rowIdPattern: string): Promise<void>

Examples:

await event.grid1.getRowByIndex(0).click();
await event.grid1.getCellByExactValue('Some value').click();
await event.grid1.selectRowByRowId('manager');

Filtering

  • openExcelStyleFilterPopup(columnName: string): Promise<void>
  • filterByColumnValueExcelStyle(columnName: string, valueToSelect: string, deselectAll?: boolean): Promise<void>
  • getRowsByColValue(colIdToMatchOn: string, valueToMatch: string): Promise<Locator[]>

Examples:

await event.grid1.openExcelStyleFilterPopup('Order number');
await event.grid1.filterByColumnValueExcelStyle('Status', 'Active');
const matchingRows = await event.grid1.getRowsByColValue('order_id', '12345');

Extracting Values

  • getCellValuesByColId(colId: string): Promise<string[]>
  • getColumnHeaderValues(): Promise<string[]>

Examples:

const customerNames = await event.grid1.getCellValuesByColId('customer_name');
const headers = await event.grid1.getColumnHeaderValues();

Validation

  • verifyGridRecordCount(expectedRecordCount: number): Promise<void>
  • hasNoRowsOverlay(): Promise<boolean>

Examples:

await event.grid1.verifyGridRecordCount(5);
expect(await event.grid1.hasNoRowsOverlay()).toBe(false);

Task bar

In model-generated tests, each Task Bar on a subject is exposed directly on the tab as task1, task2, etc.

To use the Task bar component, access the task bar directly from the generated subject.

Available methods for the Task bar component:

  • Returns all task buttons within a task bar: tasks(): Locator
await expect(event.task1.tasks()).toBeVisible();
  • Returns a task button by its ID: getTaskById(key: string): Locator
const task = event.task1.getTaskById('add-new-event');
await task.click();
  • Returns a task button by its visible label: getTaskByLabel(label: string): Locator
const task = event.task1.getTaskByLabel('Add new event');
await task.click();
  • Select a task button by its ID: clickById(key: string): Promise<void>
const task = event.task1.clickById('add-new-event');
  • Select a task button by its visible label: clickByLabel(label: string): Promise<void>
const task = event.task1.clickByLabel('Add new event');

Task tile

In model-generated tests, each Task Tiles component on a subject is exposed directly on the tab as taskTiles1, taskTiles2, etc. Each property represents one task tile container on the tab.

Available methods for the Task tiles component:

  • Returns all task tile buttons : tasks(): Locator
await expect(event.taskTiles2.tasks()).toBeVisible();
  • Returns a task tile by its ID: getTaskById(key: string): Locator
const task = event.task1.getTaskById('add-new-event');
await task.click();
  • Returns a task tile by its visible label: getTaskByLabel(label: string): Locator
const task = event.task1.getTaskByLabel('Add new event');
await task.click();
  • Select a task tile by its ID: clickById(key: string): Promise<void>
const task = event.task1.clickById('add-new-event');
  • Select a task tile by its visible label: clickByLabel(label: string): Promise<void>
const task = event.task1.clickByLabel('Add new event');

Global Components

There is a list of components that we have made easily accessibile without the need to import or initialize them.

You can use there anywhere where you have a page object, provided the original imported page object that is from Testwise.

The current list of components are:

  • export
  • listBarMenu
  • popUp
  • snackBar
  • topBar

How to access these component:

await page.components.<chooose component from list>;()

// Example 1:
const pupupHeading = await page.components.popUp.getHeadingText();

// Example 2:
const topBarTitle = await page.components.topBar.getTopBarTitle();

// Example 3:
await page.components.listBarMenu.getMenuGroupByName('My Menu Group').click();

Export

In model-generated tests, the Export component is available via the generated page components collection:

<subject>.page.components.export
note

The Export dialog must be opened through the toolbar before interacting with the export component.

Depending on the screen width and layout, the Export button may be:

  • Visible directly in the toolbar
  • Rendered inside the toolbar overflow menu (⋯)

If the button is inside the overflow menu, access it via:

event.toolbar.overflowMenu.getExportButton()

Otherwise, use:

event.toolbar.getExportButton()

Available methods in the Export component:

  1. Select the export all rows radio button and go to next step: exportAllRows(): Promise<void>
await event.page.components.export.exportAllRows();
  1. Select columns to export: selectColumns(columns: string[]): Promise<void>
const columnsToSelect: string[] = ['FirstColumnName','SecondColumnName','ThirdColumnName'];
await event.page.components.export.selectColumns(columnsToSelect);
  1. Select the Next button: nextStep(): Promise<void>
await event.page.components.export.nextStep();
note

Takes in an array of strings; for every column in the list, a click action is performed on the checkbox matching the column name.

  1. Select the export format: selectExportFormat(format: ExportFormat): Promise<void>
import { ExportFormat } from '@thinkwise/testwise';

await exportComponent.selectExportFormat(ExportFormat.CSV)

See Enumerations for more options.

  1. Complete export: completeExport(): Promise<Record<string, string[]>>
const exportedData: Record<string, string[]> = await event.page.components.export.completeExport();


// Assert
for (const [index, row] of exportedData.entries()) {
expect(row.Name, `Row ${index} has incorrect value`).toBe('ExpectedValue');
}

Pop-up

To initialize the Pop-up component:

import { PopUpComponent } from '@thinkwise/testwise';

const popup = new PopUpComponent(page);

Available Methods for the Pop-up component:

  • getHeadingText(): Promise<string | null>
  • getContentText(): Promise<string | null>
  • getContentBody(): Locator
  • getActionButtonByText(text: string): Locator

Example

const popup = new PopUpComponent(page);

await popup.getActionButtonByText('Confirm').click();

Custom controls

Initializing these controls provides actions beyond standard Playwright actions.

We have 4 control types currently:

  • Lookup dropdown
  • Combo Box
  • Date Field
  • Form Field

The Lookup Dropdown and Combo Box are both variations of a lookups component. They differ somewhat in appearance as well as in behavior under the hood, but can be clearly identified in Testwise by name

Hierarchy

Generated controls follow the subject structure:

<subject><screen component><control>

Where:

  • subject represents the generated subject object, with the screen type attached thereto
  • screen component is the screen component identifier. E.g. grid1 or form1
  • control is the lookup control identifier

Usage

Once you know the control you are targeting you will get both the standard Playwright actions to execute, as well as Testwise specific actions

await <yourSubjectHere>.<yourScreenComponentIdHere>.<yourControlNameHere>.<theActionToPerform>();

Lookup dropdown

In model-generated tests, lookup controls are automatically exposed through the generated subject structure. Each lookup is strongly typed and available directly via the subject’s form hierarchy.

No manual locator definitions or wrapper initialization are required.

Lookup controls are generated with built-in Thinkwise-specific behavior and do not require additional configuration.

Available Method

Over and above the default Playwright actions, you get the following:

lookupSelect(value: string)

Expands the lookup dropdown and then filter-and-selects by the value

await <yourSubjectHere>.<yourScreenComponentIdHere>.<youLookupField>.lookupSelect('<yourOptionHere>');

This method ensures correct interaction with Thinkwise lookup controls and abstracts away underlying UI complexity.

Combo Box

Available Method

Over and above the default Playwright actions, you get the following:

lookupSelect(value: string)

Expands the lookup dropdown and then filter-and-selects by the value

await <yourSubjectHere>.<yourScreenComponentIdHere>.<yourComboBox>.lookupSelect('<yourOptionHere>');

getValidationMessage() Retrieves the current validation message that has fired

const validationMessage = await <yourSubjectHere>.<yourScreenComponentIdHere>.<youComboBox>.getValidationMessage();

clearByClick() Clears the ComboBox selection by clicking the x button right of the currently selected option

await <yourSubjectHere>.<yourScreenComponentIdHere>.<youComboBox>.clearByClick();

Form Field

The form field gives you access to helpful methods that you do not need to build out separately such as getting the label text and retrieving validation messages

Available Method InputElement() Allows you to perform actions directly to the input nested within the field.

note

Performing actions like fill, clear, or inputValue can be done on the form field directly, and will propagate down into the input element. But as seen in the example below, if you want to assess a particular attribute on specifically the input and not the parent field container, then you need to access the Input via the InputElement() method

await expect(<yourSubjectHere>.<yourScreenComponentIdHere>.<yourFormFieldName>.InputElement()).toHaveAttribute('type', 'text');

getLabelText() Retrieves the text value of the label

const labelText = await <yourSubjectHere>.<yourScreenComponentIdHere>.<yourFormFieldName>.getLabelText();

getValidationMessage() Retrieves the current validation message that has fired

const validationMessage = await <yourSubjectHere>.<yourScreenComponentIdHere>.<yourFormFieldName>.getValidationMessage();

Date Field

The Date Field currently works the same as any other Locator object, with the fill Action having special functionality built in, to make it compatible with filling dates into the date field.

Enumerations

Enumerations are used to define a set of named constants. You can use the enumerations below in your test scripts.

Export formats:

export enum ExportFormat {
CSV = 'csv',
XLSX = 'xlsx',
XLS = 'xls'
}

Types

Universal login options:

export type UniversalLoginOptions = {
username?: string;
password?: string;
serviceUrl?: string;
metaEndpoint?: string;
config?: UniversalConfigOptions;
};

Universal config options:

export type UniversalConfigOptions = {
barcodeScannerSymbologies?: string;
cortexEnabledSymbologies?: string[];
cortexLicense?: string;
debugMode?: boolean;
devDisableProcessFlows?: boolean;
useFormFieldBackgroundColor?: boolean;
defaultApplication?: string;
defaultPlatform?: number;
loginOptionsDisabled?: boolean;
loginOptionsHidden?: boolean;
installNotificationDisabled?: boolean;
enableDragDrop?: boolean;
installNotificationExpirationInDays?: number;
spacingMode?: string;
serviceUrl?: string;
useServiceWorker?: boolean;
};

Did not find what you were looking for?

For anything else you need to do which we do not cater for specifically, you can review the Playwright documentation for available functionality.


Was this article helpful?