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
21 changes: 21 additions & 0 deletions demo/.teapie/init.csx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,27 @@ tp.RegisterTestDirective(
}
);

tp.RegisterTestDirective(
"JSON-HAS-ID-PROPERTY",
TestDirectivePatternBuilder
.Create("JSON-HAS-ID-PROPERTY")
.AddStringParameter("VariableName")
.Build(),
(_) => $"Response should be valid JSON with ID property.",
async (response, parameters) =>
{
try
{
dynamic body = await tp.Response.GetBodyAsExpandoAsync();
tp.SetVariable(parameters["VariableName"], body.Id);
}
catch (Exception ex)
{
Fail($"Response should be valid JSON with ID property. {ex.Message}");
}
}
);

// CUSTOM CLASS DEFINITIONS

// Custom authentication provider definition
Expand Down
1 change: 1 addition & 0 deletions demo/Tests/002-Cars/001-Add-Car-req.http
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Content-Type: application/json
// Separate multiple requests in a single .http file with a line containing '3 hashtags' separator:

# @name GetNewCarRequest
## TEST-JSON-HAS-ID-PROPERTY: IdFromDirective
// Access the body and headers of a named request/response using this syntax.
// For JSON bodies, use JPath to retrieve properties. For XML, use XPath.
GET {{ApiBaseUrl}}{{ApiCarsSection}}/{{AddCarRequest.request.body.$.Id}}
2 changes: 2 additions & 0 deletions demo/Tests/002-Cars/001-Add-Car-test.csx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ await tp.Test("Identifiers of added and retrieved cars should match.", async ()
dynamic requestJson = await tp.Requests["AddCarRequest"].GetBodyAsExpandoAsync();
dynamic responseJson = await tp.Responses["GetNewCarRequest"].GetBodyAsExpandoAsync();

var idFromDirective = tp.GetVariable<long>("IdFromDirective");
Equal(requestJson.Id, responseJson.Id);
Equal(requestJson.Id, idFromDirective);

// Each variable can have none or multiple tags ('cars', 'ids' in this case).
tp.SetVariable("NewCarId", requestJson.Id, "cars", "ids");
Expand Down
9 changes: 9 additions & 0 deletions docs/docs/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ If no retry strategy is explicitly selected, the **default strategy from `Polly.
| **Purpose** | Sets the maximum allowed delay between retries. |
| **Parameters** | `hh:mm:ss.fff` – The maximum delay time before retrying a failed request. |

#### `## RETRY-UNTIL-TEST-PASS` Directive

| | |
|----------------------|----------------|
| **Syntax** | `## RETRY-UNTIL-TEST-PASS: <test-name>` |
| **Example Usage** | `## RETRY-UNTIL-TEST-PASS: Identifier should be a positive integer` |
| **Purpose** | Retries the request until the defined test passes. |
| **Parameters** | `test-name` – The name of test defined in post-response .csx script. (tp.Test(`test-name`, () => )) |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor grammatical improvements needed in the Parameters field.

The Parameters description has two issues:

  1. Missing articles: "The name of test defined in post-response .csx script" should include articles for better readability.
  2. The nested backticks in the parenthetical example may not render correctly in Markdown.
📝 Proposed fix
-| **Parameters** | `test-name` – The name of test defined in post-response .csx script. (tp.Test(`test-name`, () => )) |
+| **Parameters** | `test-name` – The name of a test defined in a post-response .csx script (e.g., `tp.Test("test-name", () => { })`). |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| **Parameters** | `test-name` – The name of test defined in post-response .csx script. (tp.Test(`test-name`, () => )) |
| **Parameters** | `test-name` – The name of a test defined in a post-response .csx script (e.g., `tp.Test("test-name", () => { })`). |
🤖 Prompt for AI Agents
In `@docs/docs/directives.md` at line 104, Update the Parameters line for
`test-name` to correct grammar and avoid nested backticks: change "The name of
test defined in post-response .csx script." to "The name of the test defined in
the post-response .csx script." and rewrite the parenthetical example so it
doesn't nest backticks (e.g., show the example with only one level of code
markup or escape the inner backticks for the `tp.Test` usage such as: (for
example: tp.Test("test-name", () => { ... })). Ensure the parameter label
`test-name` and the reference to tp.Test remain present and clear.


Comment thread
coderabbitai[bot] marked this conversation as resolved.
### Testing Directives

#### `## TEST-EXPECT-STATUS` Directive
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</PropertyGroup>

<PropertyGroup>
<Version>1.5.0</Version>
<Version>1.5.1</Version>
<Authors>Matej Grochal</Authors>
<Company>KROS a.s.</Company>
<Copyright>Copyright © KROS a.s.</Copyright>
Expand Down
6 changes: 3 additions & 3 deletions src/TeaPie/Testing/ExecuteScheduledTestsStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@

namespace TeaPie.Testing;

internal class ExecuteScheduledTestsStep(ITestScheduler scheduler, IRegistrator tester) : IPipelineStep
internal class ExecuteScheduledTestsStep(ITestScheduler scheduler, ITester tester) : IPipelineStep
{
private readonly ITestScheduler _scheduler = scheduler;
private readonly IRegistrator _tester = tester;
private readonly ITester _tester = tester;

public async Task Execute(ApplicationContext context, CancellationToken cancellationToken = default)
{
while (_scheduler.HasScheduledTest())
{
var test = _scheduler.Dequeue();
await _tester.Test(test.Name, test.Function);
await _tester.ExecuteOrSkipTest(test, test.TestCase);

context.Logger.LogDebug("Scheduled test with name '{TestName}' was executed.", test.Name);
}
Expand Down
57 changes: 56 additions & 1 deletion tests/TeaPie.Tests/ApplicationPipelineShould.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
using NSubstitute;
using FluentAssertions;
using NSubstitute;
using TeaPie.Pipelines;
using TeaPie.Reporting;
using TeaPie.Scripts;
using TeaPie.StructureExploration;
using TeaPie.TestCases;
using TeaPie.Testing;
using TeaPie.Tests.Pipelines;

namespace TeaPie.Tests;
Expand Down Expand Up @@ -96,6 +102,55 @@ public async Task EnableAddingStepsDuringPipelineRun()
await pipeline.Run(context);
}

[Fact]
public async Task ExecuteScheduledTestsBeforeRegisteredTests()
{
var pipeline = new ApplicationPipeline();
var executionOrder = new List<string>();

var testCase = new TestCase(new InternalFile("test.http", "test.http", null!));
var testCaseContext = new TestCaseExecutionContext(testCase);

var accessor = Substitute.For<ITestCaseExecutionContextAccessor>();
accessor.Context.Returns(testCaseContext);

var reporter = Substitute.For<ITestResultsSummaryReporter>();

var tester = Substitute.For<ITester>();
tester.ExecuteOrSkipTest(Arg.Any<Test>(), Arg.Any<TestCase?>())
.Returns(callInfo =>
{
var test = callInfo.Arg<Test>();
executionOrder.Add(test.Name);
return Task.FromResult(test);
});

var scheduler = new TestScheduler();
var scheduledTest = CreateTest("scheduled-test", testCase);
scheduler.Schedule(scheduledTest);

var registeredTest = CreateTest("registered-test", testCase);
testCaseContext.RegisterTest(registeredTest);

var executeScheduledTestsStep = new ExecuteScheduledTestsStep(scheduler, tester);
var runScriptTestsStep = new RunScriptTestsStep(accessor, reporter, tester);

pipeline.AddSteps(executeScheduledTestsStep);
pipeline.AddSteps(runScriptTestsStep);

await pipeline.Run(CreateApplicationContext(string.Empty));

executionOrder.Should().HaveCount(2);
executionOrder[0].Should().Be("scheduled-test");
executionOrder[1].Should().Be("registered-test");
}

private static Test CreateTest(string name, TestCase testCase)
{
var result = new TestResult.NotRun { TestName = name, TestCasePath = "test.http" };
return new Test(name, false, () => Task.CompletedTask, result, testCase);
}

private static ApplicationContext CreateApplicationContext(string path)
=> new ApplicationContextBuilder()
.WithPath(path)
Expand Down