Skip to content

Commit d16cc6b

Browse files
committed
Add structured test logging and enhanced HTML report generation
- Add IntegrationTestBase and TestOutputHelper for structured test output - Add logging calls across all integration test files - Move report scripts to Scripts folder, add enhanced HTML report generator - Update .gitignore for test artifacts - Remove hardcoded UID from docfx example
1 parent 3ce7726 commit d16cc6b

48 files changed

Lines changed: 7050 additions & 98 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ Contentstack.Core.Tests/app.config
3333
# Test Results
3434
TestResults/
3535
test-report*.html
36+
test-report-enhanced*.html
3637
*.trx
38+
docs
3739

3840
# Security Scan Reports
3941
SECURITY-SCAN-REPORT.txt

.talismanrc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ fileignoreconfig:
4040
- filename: Contentstack.Core.Tests/Integration/ReferenceTests/MultiReferenceTest.cs
4141
checksum: 6b24eafdffb7fcb92d0e118b1092c151fed75505fc50bb138d706a51aed606d7
4242
- filename: Contentstack.Core.Tests/Integration/VariantsTests/EntryVariantsComprehensiveTest.cs
43-
checksum: 7afa0f5d5f821f224c7e0df3e589d9138cd69cb4e7463501a33474be582150cf
43+
checksum: 5c16d15ac80dfcec8b85b67c83bcd2e962b365a95f4a8553f52fc3bc22d15fee
4444
- filename: Contentstack.Core.Tests/Integration/StackTests/StackOperationsComprehensiveTest.cs
4545
checksum: 522fff363dad0bb89b2d1ab263c569037cf087227c4f420164168ec03788edd4
4646
- filename: Contentstack.Core.Tests/Integration/ContentTypeTests/ContentTypeOperationsTest.cs
@@ -83,4 +83,10 @@ fileignoreconfig:
8383
checksum: 67c8afb436287676e0db3a62a9213d800239cf5bb543cc4d81f438655abf0e1f
8484
- filename: Contentstack.Core.Tests/generate_html_report.py
8585
checksum: b4bec9ef853703e989b3d8077edc5c3ec6ea13a23826699d8beca5e87323e128
86+
- filename: Contentstack.Core.Tests/Helpers/IntegrationTestBase.cs
87+
checksum: fe8a38f19e916767f6a016b33d4e8cd12316aaf70a8a46bcd6e44fedcbe921d7
88+
- filename: Contentstack.Core.Tests/Helpers/TestOutputHelper.cs
89+
checksum: 70eec33b6a5b3d1adada6309837d88c12f677e99e87d8517cb7f9a23537e1a8c
90+
- filename: Scripts/generate_enhanced_html_report.py
91+
checksum: e31c1372ea6e1cd1381c9533ba89b95edf746b36e4a1098d4aa51fba296ca928
8692
version: "1.0"
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Xunit.Abstractions;
4+
using Contentstack.Core.Configuration;
5+
using Contentstack.Core.Models;
6+
7+
namespace Contentstack.Core.Tests.Helpers
8+
{
9+
/// <summary>
10+
/// Base class for integration tests with built-in enhanced logging support
11+
/// Provides TestOutputHelper and common helper methods for logging
12+
/// </summary>
13+
public abstract class IntegrationTestBase
14+
{
15+
protected readonly ITestOutputHelper Output;
16+
protected readonly TestOutputHelper TestOutput;
17+
18+
protected IntegrationTestBase(ITestOutputHelper output)
19+
{
20+
Output = output;
21+
TestOutput = new TestOutputHelper(output, GetType().Name);
22+
}
23+
24+
/// <summary>
25+
/// Log test arrangement step with context
26+
/// </summary>
27+
protected void LogArrange(string description, Dictionary<string, object> context = null)
28+
{
29+
TestOutput.LogStep("Arrange", description);
30+
31+
if (context != null)
32+
{
33+
foreach (var kvp in context)
34+
{
35+
TestOutput.LogContext(kvp.Key, kvp.Value);
36+
}
37+
}
38+
}
39+
40+
/// <summary>
41+
/// Log test action step
42+
/// </summary>
43+
protected void LogAct(string description)
44+
{
45+
TestOutput.LogStep("Act", description);
46+
}
47+
48+
/// <summary>
49+
/// Log test assertion step
50+
/// </summary>
51+
protected void LogAssert(string description)
52+
{
53+
TestOutput.LogStep("Assert", description);
54+
}
55+
56+
/// <summary>
57+
/// Log HTTP GET request with standard Contentstack headers
58+
/// </summary>
59+
protected void LogGetRequest(string url, string variantUid = null, Dictionary<string, string> additionalHeaders = null)
60+
{
61+
var headers = new Dictionary<string, string>
62+
{
63+
{ "api_key", TestDataHelper.ApiKey },
64+
{ "access_token", TestDataHelper.DeliveryToken },
65+
{ "Content-Type", "application/json" }
66+
};
67+
68+
if (!string.IsNullOrEmpty(variantUid))
69+
{
70+
headers["x-cs-variant-uid"] = variantUid;
71+
}
72+
73+
if (additionalHeaders != null)
74+
{
75+
foreach (var header in additionalHeaders)
76+
{
77+
headers[header.Key] = header.Value;
78+
}
79+
}
80+
81+
TestOutput.LogRequest("GET", url, headers);
82+
}
83+
84+
/// <summary>
85+
/// Log successful HTTP response
86+
/// </summary>
87+
protected void LogSuccessResponse(int statusCode = 200, string statusText = "OK", Dictionary<string, string> headers = null)
88+
{
89+
var responseHeaders = headers ?? new Dictionary<string, string>
90+
{
91+
{ "content-type", "application/json" }
92+
};
93+
94+
TestOutput.LogResponse(statusCode, statusText, responseHeaders);
95+
}
96+
97+
/// <summary>
98+
/// Log assertion with expected and actual values
99+
/// </summary>
100+
protected void LogAssertion(string name, object expected, object actual)
101+
{
102+
var passed = AreEqual(expected, actual);
103+
TestOutput.LogAssertion(name, expected, actual, passed);
104+
}
105+
106+
/// <summary>
107+
/// Log context information
108+
/// </summary>
109+
protected void LogContext(string key, object value)
110+
{
111+
TestOutput.LogContext(key, value);
112+
}
113+
114+
/// <summary>
115+
/// Helper to check equality for logging
116+
/// </summary>
117+
private bool AreEqual(object expected, object actual)
118+
{
119+
if (expected == null && actual == null) return true;
120+
if (expected == null || actual == null) return false;
121+
return expected.Equals(actual) || expected.ToString() == actual.ToString();
122+
}
123+
124+
/// <summary>
125+
/// Create Contentstack client with standard configuration
126+
/// </summary>
127+
protected ContentstackClient CreateClient()
128+
{
129+
var options = new ContentstackOptions()
130+
{
131+
Host = TestDataHelper.Host,
132+
ApiKey = TestDataHelper.ApiKey,
133+
DeliveryToken = TestDataHelper.DeliveryToken,
134+
Environment = TestDataHelper.Environment,
135+
Branch = TestDataHelper.BranchUid
136+
};
137+
138+
return new ContentstackClient(options);
139+
}
140+
141+
/// <summary>
142+
/// Build API URL for entry fetch
143+
/// </summary>
144+
protected string BuildEntryUrl(string contentType, string entryUid, Dictionary<string, string> queryParams = null)
145+
{
146+
var url = $"https://{TestDataHelper.Host}/v3/content_types/{contentType}/entries/{entryUid}";
147+
148+
if (queryParams != null && queryParams.Count > 0)
149+
{
150+
var queryString = string.Join("&",
151+
System.Linq.Enumerable.Select(queryParams, kvp => $"{kvp.Key}={kvp.Value}"));
152+
url += "?" + queryString;
153+
}
154+
155+
return url;
156+
}
157+
158+
/// <summary>
159+
/// Build API URL for query
160+
/// </summary>
161+
protected string BuildQueryUrl(string contentType, Dictionary<string, string> queryParams = null)
162+
{
163+
var url = $"https://{TestDataHelper.Host}/v3/content_types/{contentType}/entries";
164+
165+
if (queryParams != null && queryParams.Count > 0)
166+
{
167+
var queryString = string.Join("&",
168+
System.Linq.Enumerable.Select(queryParams, kvp => $"{kvp.Key}={kvp.Value}"));
169+
url += "?" + queryString;
170+
}
171+
172+
return url;
173+
}
174+
}
175+
}

0 commit comments

Comments
 (0)