Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions content/docs/analyzers/TestAutomationCop/TA0002.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
+++
title = 'Actions cannot be invoked on a part page opened directly through its own TestPage variable'
linkTitle = 'TA0002'

[params]
id = 'TA0002'
severity = 'Warning'
category = 'Usage'
codeAction = false
ignoreObsolete = false
+++

A `ListPart` or `CardPart` page opened directly through its own `TestPage` variable renders no actions at runtime. The platform resolves actions only when the part is hosted inside another page and reached through its `part(...)` control. Calling `Invoke()`, `Enabled()`, or `Visible()` on any action of a directly opened part page fails with:

> The action with ID = xxx is not found on the page.

To reach the action in a test, open the hosting page and invoke the action through the part control: `MainPage.SubPagePart.MyAction.Invoke()`.

### Example

{{< highlight al "hl_lines=25" >}}
page 50100 "Item Subpage"
{
PageType = ListPart;
SourceTable = Item;

actions
{
area(processing)
{
action(UpdatePrices) { }
}
}
}

codeunit 50100 "Item Test"
{
Subtype = Test;

[Test]
procedure PriceUpdateTest()
var
ItemSubPage: TestPage "Item Subpage";
begin
ItemSubPage.OpenView();
ItemSubPage.UpdatePrices.Invoke(); // Action 'UpdatePrices' cannot be invoked on page 'Item Subpage' opened directly because its PageType is ListPart; invoke it through the part control of the hosting page instead. [TA0002]
end;
}
{{< /highlight >}}

Open the hosting page instead and invoke the action through its part control.

{{< highlight al "hl_lines=25" >}}
page 50101 "Item Card"
{
PageType = Card;
SourceTable = Item;

layout
{
area(content)
{
part(ItemLines; "Item Subpage") { }
}
}
}

codeunit 50100 "Item Test"
{
Subtype = Test;

[Test]
procedure PriceUpdateTest()
var
ItemCard: TestPage "Item Card";
begin
ItemCard.OpenView();
ItemCard.ItemLines.UpdatePrices.Invoke();
end;
}
{{< /highlight >}}

### When the diagnostic is reported

- The receiver is a `TestPage` variable (local, global, or `var` parameter) whose target page has `PageType = ListPart` or `PageType = CardPart`.
- The call is `Invoke()`, `Enabled()`, or `Visible()` on any action of that page β€” these are the only members of the built-in `TestAction` class, and all three fail identically at runtime.
- Actions added by a `pageextension` that extends the part page are included.
- Obsolete code is not exempt: an obsolete part page, an `[Obsolete]` test method and an `ObsoleteState = Pending` test codeunit are all reported, because the test runner still executes the test and the runtime failure is real.

### Exception

The diagnostic is not raised for:

- **Field access** on a directly opened part page β€” fields work without the hosting page.
- **`OpenView()`, `OpenEdit()`, `OpenNew()`** and other `TestPage` built-in methods β€” these are not `TestAction` members.
- **Built-in system actions** `OK()`, `Cancel()`, `Yes()`, `No()`, `View()`, `Edit()` β€” these are methods of the `TestPage` itself, not actions declared on the part page.
- **`TestRequestPage`** variables β€” request pages are not `ListPart` or `CardPart`.

```al
#pragma warning disable TA0002 // This test deliberately asserts the platform error for an action on a directly opened part.
asserterror ItemSubPage.UpdatePrices.Invoke();
#pragma warning restore TA0002
```

### See also

- [TestPage Data Type](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/methods-auto/testpage/testpage-data-type) on Microsoft Learn
3 changes: 2 additions & 1 deletion content/docs/analyzers/TestAutomationCop/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ type: docs
no_list: true
---

TestAutomationCop inspects test codeunits and is silent on production code. It flags test procedures whose structure or attributes keep the test runner from executing them as intended, such as a global procedure in a test codeunit that is not marked as a test method.
TestAutomationCop inspects test codeunits and is silent on production code. It flags test code whose structure keeps the test runner from executing it as intended, such as a missing `[Test]` attribute or an action invoked on a part page that renders no actions at runtime.

## Rules

| ID | Title | Severity | Enabled | Code Fix |
|---|---|---|---|---|
| [TA0001](ta0001/) | Global procedures in test codeunits must be test methods | Warning | βœ“ | |
| [TA0002](ta0002/) | Actions cannot be invoked on a part page opened directly through its own TestPage variable | Warning | βœ“ | |