Skip to main content
Release notes

Release notes Testwise 0.2.111

Related products:Testwise
  • Nov 13, 2026 8:01 AM UTC
  • 0 replies
  • 15 views

Hello everyone,

This release makes tests easier to write and more stable, with new ways to work with grids, task buttons, and date fields. Grid row counts now include only data rows, so tests that add 1 for the header row need an update. Testwise now also works with Universal 2026.3.11.

Tests can now do more with action bars and grids: Generated action bars have a getter for every task button, so your editor suggests task buttons while you type. For grids, you can read the values of the summary row and select a row without starting an edit.

Tests also no longer depend on the date settings of the test user, because date fields are filled the same way under every date format.

Several quality-of-life improvements round out this release. Timeout errors now say what Testwise was waiting for, so you find the cause of a failed test faster. Fixes for grid column values, combo boxes, prefilters, date fields, and names with accents make tests more reliable.

 

Contents

 

Before you upgrade

 

Breaking

Grid row counts limited to data rows

Previously, the rows of a grid also included the header row, and the summary row when the grid had one. Now, the rows of a grid include only its data rows (@thinkwise/testwise > Grid > rows()). The number of rows equals the number of records a user sees, also in grids with a summary row. Checking the record count with verifyGridRecordCount() works as before, and now also in grids with a summary row.

For example, for a grid that shows 3 events:

const event = await page.subject.EventMain;

// 0.2.105: the header row was counted too
await expect(event.grid2.rows()).toHaveCount(3 + 1);

// 0.2.111: only the data rows are counted
await expect(event.grid2.rows()).toHaveCount(3);

After updating to 0.2.111, tests that add 1 for the header row fail until you remove the extra 1.

To fix these tests:

  1. Look in your tests for row counts that add 1 for the header row, for example, toHaveCount(3 + 1).
  2. Remove the extra 1.
  3. Run the tests.

 

New

Support for Universal 2026.3.11

Testwise 0.2.111 now supports Universal 2026.3.11. The Filter pop-up is different compared to previous versions of the Universal UI. This affects how Testwise interacts with the Filter pop-up in tests.

In earlier versions, Select field in the advanced filter was a button. In Universal 2026.3.11, Select field in the advanced filter is a combo box. Previously, selecting a field timed out, because the test could not find the picker. @thinkwise/testwise > FilterPopup > selectField() and addField() now finds the picker in both versions.

In Universal 2026.3.11, a date interval row gets a new, empty interval row below it as soon as it has a value. This allows the date column to have multiple interval rows. @thinkwise/testwise > FilterPopup > intervalSelector(), intervalSelectorInput(), openInterval(), and setInterval() use the column's first interval row by default.

To use a different one, pass its position among the column's interval rows (counting from 0) as index.

For example, set and check the interval of a date column's second interval row in the advanced filter:

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

const filterPopup = new FilterPopup(page);
await filterPopup.setInterval('event-date', 'year', { index: 1 });

await expect(filterPopup.intervalSelectorInput('event-date', { index: 1 })).toHaveValue('Year');

 

Getters for every task button on generated action bars

You can now use a generated getter for every task button on the action bar of a generated subject.

Previously, the generated action bar only had getters for the CRUD buttons, such as Add, Save, and Delete. To reach a task button, you had to use getTaskButtonById() with the id as the page renders it, with hyphens instead of underscores, for example, send-invitation. getTaskButtonById() now also accepts the task id as it is written in the model.

Your editor now suggests task buttons while you type. When a task is removed from the model, the editor shows an error in the test instead of the test waiting for a button that is not there.

The getters are in Test project > test-artifacts > subjects > [Subject] > Components > [Subject][Variant]ActionBar.ts. In a test, you reach them through page.subject > [subject, such as EventMain] > [toolbar] > [task name]Button.

To use a task getter:

  1. Update Testwise to 0.2.111 and run npx testwise sync.
  2. In a test, type the toolbar property of a generated subject, followed by a dot. Your editor lists every task on that action bar as [task name]Button. For example, task send_invitation is listed as sendInvitationButton.
  3. Call click() on it to start the task.

For example, a test that sends the invitation for an event:

const event = await page.subject.EventMain;

await event.toolbar3574C040.sendInvitationButton.click();

Tasks with custom display type 4 are not standard toolbar buttons, so they have no getter.

 

Summary row values in grids

You can now read the summary row that a grid shows when a column has a count or sum. Tests can check the totals and counts a user sees in a grid, for example, that the sum of a column is updated after a record is added.

The methods are in @thinkwise/testwise > Grid > getSummaryCellByColId() and getSummaryValueByColId(). Generated grid columns have getSummaryCell() and getSummaryValue().

To check a summary value:

  1. In a test, get the generated subject whose grid shows a summary row.
  2. Call getSummaryCellByColId() on the grid with the id of the column.
  3. Check the cell with toHaveText(). The check passes when the summary row shows that value.

To get the text itself, use getSummaryValueByColId() instead. It returns null when the column has no summary.

For example, check that the total number of attendees in the grid is 250:

const event = await page.subject.EventMain;

await expect(event.grid2.getSummaryCellByColId('max_attendees')).toHaveText('250');

 

Grid row selection without starting an edit

You can now select a grid row by clicking a column you choose (@thinkwise/testwise > Grid > selectRowByIndex()). Previously, the usual way was to click the middle of the row. On an auto-edit grid, that click could land in an editable cell, opening an editor and changing the record instead of selecting it. Clicking a read-only column now selects the row without editing it.

To select a row without starting an edit:

  1. Choose a column that is read-only in the grid, such as the key column.
  2. In a test, call selectRowByIndex() on the grid with the row number (counting from 0) and the id of that column. The row becomes the active record, and no editor opens.

For example, select the first event without editing it:

const event = await page.subject.EventMain;

await event.grid2.selectRowByIndex(0, 'event_id');

 

Date fields filled the same way under every date format

Tests no longer depend on the date settings of the test user. A date written as YYYY-MM-DD is now entered as the same date for every test user, no matter their date format (for example, DD-MM-YYYY or MM/DD/YYYY). This works in the date fields of forms (@thinkwise/testwise > DateControl > fill()) and in the date inputs of the Filter pop-up (@thinkwise/testwise > FilterPopup > setDate()).

Previously, a date was typed exactly as written, so a test only entered the right date for users with the date format it was written for. A date written another way is still typed as before.

To enter a date:

  1. When you fill a date field of a generated form (named [column]DatePicker), write the date as YYYY-MM-DD, for example, fill('2025-03-15'). If the field has a time, add it as YYYY-MM-DD HH:mm:ss.
  2. For a date in the filter pop-up, call setDate() with the field id and the date. FilterPopup.setDate() is new, so it only accepts YYYY-MM-DD or YYYY-MM-DD HH:mm:ss, and gives an error for any other format.
  3. Run the test with any test user. The field shows 15 March 2025 in that user's date format.

For example, enter an event date and filter events on a date:

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

const event = await page.subject.EventMain;
await event.form1.eventDateDatePicker.fill('2025-03-15');

const filterPopup = new FilterPopup(page);
await filterPopup.setDate({ fieldId: 'event-datetime', part: 'date', value: '2024-01-15' });

 

Changed

Clearer timeout errors

Previously, when a Testwise wait timed out, the error only said that the wait had timed out. Now, the error also says what Testwise was waiting for, how many times it checked, and the last value it saw. A failed test tells you directly what did not happen, so you find the cause faster.

This applies to @thinkwise/testwise > Grid > verifyGridRecordCount() and hasNoRowsOverlay(), and to the waits during login, user simulation, and the delete-all-rows pop-up.

For example, the error when a grid shows 4 records where the test expects 5:

pollUntil timeout after 10000ms waiting for the grid to show 5 records; 47 attempts over 10066ms, last value: 4

 

Fixed

  • In a grid with a summary row (count or sum), reading the values of a column also returned the summary value, so the list had one value too many (@thinkwise/testwise > Grid > getCellValuesByColId()). Reading a column now returns only the values of the records in the grid.

    A test that worked around this issue, for example, by dropping the last value from the list, now fails. So does a test that expects the summary value in the list. Remove the workaround, and read the summary value on its own with the methods from Summary row values in grids.

  • When selecting a combo box option whose text contains a space, such as Human resources, the test waited for the option until it timed out (@thinkwise/testwise > FormComboBox > selectOption() and lookupSelect()). Every option can now be selected by its visible text.

  • When saving a filter as a prefilter (@thinkwise/testwise > FilterPopup > applySaveAsPrefilterWithName() and saveAsPrefilterPopup()), the test could click the wrong Save, because the Filter pop-up and the Save as pop-up each have one. The step also finished while both pop-ups were still closing, so the next click could land on one of them. Now, the test clicks Save in the Save as pop-up and continues only after both pop-ups have closed.

  • Filling, clearing, and reading a date field of a generated form (@thinkwise/testwise > DateControl > fill(), clear(), inputValue(), and inputElement()) acted on the whole form instead of on the date field. Filling a date only worked when the click happened to land in that field, and checking the field's value could not pass.

  • npx testwise sync stopped with an error when the model had a screen type or table with an accent in its name, such as Algemeen hiërarchie, because the generated code did not compile.

  • After npx testwise sync, a subject or variant with an accent in its name was missing from page.subject.

 

Questions or suggestions?

Do you have any questions or suggestions? Let us know in the Thinkwise Community!

This topic has been closed for replies.