diff --git a/TESTING.md b/TESTING.md index 5107fed..f06d98a 100644 --- a/TESTING.md +++ b/TESTING.md @@ -21,6 +21,7 @@ The `tests/` IIS application assumes the repository layout keeps `tests/`, `publ | Create | `tests/sync-webconfigs.vbs` | Utility script to mirror `tests/web.config` into nested test folders | | Create | `tests/bootstrap.asp` | Shared test bootstrap and runtime reset helpers | | Create | `tests/PlainRunnerTheme.asp` | Local runner theme that removes CDN dependence from the test UI | +| Create | `tests/support/HttpCaptureHelpers.asp` | Shared HTTP capture helpers for rendered-page assertions | | Create | `tests/test-manifest.asp` | Single source of truth for registered test pages | | Create | `tests/run-all.asp` | Browser runner that aggregates all test pages | | Vendor | `tests/aspunit/Lib/*` | Upstream aspunit framework files | @@ -29,6 +30,9 @@ The `tests/` IIS application assumes the repository layout keeps `tests/`, `publ | Create | `tests/unit/TestControllerRegistry.asp` | Controller whitelist/format unit tests | | Create | `tests/component/TestHomeController.asp` | Controlled component-level controller test | | Create | `tests/integration/TestMvcDispatch.asp` | Narrow router/dispatch smoke test | +| Create | `tests/integration/TestRoutes.asp` | Route-helper/config integration coverage | +| Create | `tests/integration/TestConfigSettings.asp` | Nested config and fallback behavior coverage | +| Create | `tests/integration/TestRenderedOutput.asp` | Production-page output assertions through safe HTTP capture | | Reference | `public/web.config` | Source of mirrored config keys for the test app | | Reference | `core/helpers.asp` | Helper functions and config-loading behavior under test | | Reference | `core/mvc.asp` | Dispatcher behavior used by the smoke test | @@ -43,6 +47,8 @@ The `tests/` IIS application assumes the repository layout keeps `tests/`, `publ 4. Ensure parent paths are allowed for the `tests/` app. This repo ships `tests/web.config` with `enableParentPaths="true"` because the bootstrap and integration pages include sibling files from `../core/` and `../app/`. 5. Browse to the `tests/` app root or directly to `run-all.asp`. 6. If you change `tests/web.config`, run `cscript //nologo tests\sync-webconfigs.vbs` to refresh the nested copies used by the unit, component, and integration pages. +7. If your production app is not served from the same host root as the `tests/` app, set `ProductionAppBaseUrl` in `tests/web.config` and re-run the sync script so rendered-output tests know where to send HTTP requests. + Example: `http://localhost/` for a root site, or `http://localhost/MyClassicApp/` for a virtual-directory app. Example layout: @@ -58,6 +64,7 @@ Example layout: - helper/config access - controller registry access - router reset +- `tests/support/HttpCaptureHelpers.asp` provides safe HTTP-based page capture for rendered output assertions against the production app. The integration test page includes `core/mvc.asp` directly because that is the only first-wave test that needs dispatcher behavior. @@ -82,7 +89,7 @@ aspunit renders a UI in runner mode and loads each registered page with `?task=t 1. Choose the right folder: - `tests/unit/` for deterministic helper or registry tests - `tests/component/` for direct controller/object tests with controlled setup - - `tests/integration/` for narrow runtime smoke coverage + - `tests/integration/` for narrow runtime smoke coverage, config behavior, or rendered-page capture 2. Create a new `.asp` file that: - includes `../aspunit/Lib/ASPUnit.asp` - includes `../bootstrap.asp` @@ -111,6 +118,8 @@ aspunit renders a UI in runner mode and loads each registered page with `?task=t - `run-all.asp` loads in the separate `tests/` IIS app. - All manifest pages appear in the runner. - Helper, registry, component, and integration suites all execute. +- Route-helper/config integration assertions execute from the same isolated IIS app. +- Rendered-page capture assertions can verify production HTML and status codes without polluting aspunit JSON responses. - Re-running the suite produces stable results. - The production site under `public/` still exposes no test runner pages or test routes. diff --git a/tests/component/web.config b/tests/component/web.config index ed300d3..3bf406c 100644 --- a/tests/component/web.config +++ b/tests/component/web.config @@ -2,9 +2,11 @@ + + diff --git a/tests/integration/TestConfigSettings.asp b/tests/integration/TestConfigSettings.asp new file mode 100644 index 0000000..60089d6 --- /dev/null +++ b/tests/integration/TestConfigSettings.asp @@ -0,0 +1,41 @@ + + + +<% +Call ASPUnit.AddModule( _ + ASPUnit.CreateModule( _ + "Config Integration Tests", _ + Array( _ + ASPUnit.CreateTest("NestedTestPageReadsMirroredConfigValue"), _ + ASPUnit.CreateTest("MissingConfigKeyReturnsNothingSentinel"), _ + ASPUnit.CreateTest("ProductionAppBaseUrlSupportsBlankOrConfiguredValue") _ + ), _ + ASPUnit.CreateLifeCycle("SetupConfigIntegration", "TeardownConfigIntegration") _ + ) _ +) + +Call ASPUnit.Run() + +Sub SetupConfigIntegration() + Call ResetTestRuntime() +End Sub + +Sub TeardownConfigIntegration() + Call ResetTestRuntime() +End Sub + +Function NestedTestPageReadsMirroredConfigValue() + Call ASPUnit.Equal(GetAppSetting("Error404RedirectSeconds"), "5", "Nested integration pages should read mirrored config values from their local web.config") +End Function + +Function MissingConfigKeyReturnsNothingSentinel() + Call ASPUnit.Equal(GetAppSetting("DefinitelyMissingSetting"), "nothing", "Missing config keys should return the existing nothing sentinel") +End Function + +Function ProductionAppBaseUrlSupportsBlankOrConfiguredValue() + Dim configuredUrl + configuredUrl = GetAppSetting("ProductionAppBaseUrl") + + Call ASPUnit.Ok((configuredUrl = "" Or configuredUrl = "nothing" Or InStr(configuredUrl, "http://") = 1 Or InStr(configuredUrl, "https://") = 1), "ProductionAppBaseUrl should be either blank for host fallback or an explicit absolute URL") +End Function +%> diff --git a/tests/integration/TestRenderedOutput.asp b/tests/integration/TestRenderedOutput.asp new file mode 100644 index 0000000..fc76c54 --- /dev/null +++ b/tests/integration/TestRenderedOutput.asp @@ -0,0 +1,52 @@ + + + + +<% +Call ASPUnit.AddModule( _ + ASPUnit.CreateModule( _ + "Rendered Output Capture Tests", _ + Array( _ + ASPUnit.CreateTest("HomePageReturnsWelcomeMarkup"), _ + ASPUnit.CreateTest("NotFoundPageReturns404Markup") _ + ), _ + ASPUnit.CreateLifeCycle("SetupRenderedOutput", "TeardownRenderedOutput") _ + ) _ +) + +Call ASPUnit.Run() + +Sub SetupRenderedOutput() + Call ResetTestRuntime() +End Sub + +Sub TeardownRenderedOutput() + Call ResetTestRuntime() +End Sub + +Function HomePageReturnsWelcomeMarkup() + Dim responseData + Dim bodyContains, message + Set responseData = FetchPage("/") + + bodyContains = (InStr(responseData.Item("body"), "Welcome to RouteKit Classic ASP") > 0) + message = "Home page request should return welcome markup. URL=" & responseData.Item("url") & "; Status=" & responseData.Item("status") & "; Snippet=" & Left(CStr(responseData.Item("body")), 160) + + Call ASPUnit.Ok((responseData.Item("status") = 200 And bodyContains), message) + + Set responseData = Nothing +End Function + +Function NotFoundPageReturns404Markup() + Dim responseData + Dim bodyContains, message + Set responseData = FetchPage("/404") + + bodyContains = (InStr(responseData.Item("body"), "404 - Page Not Found") > 0) + message = "404 request should return not-found markup. URL=" & responseData.Item("url") & "; Status=" & responseData.Item("status") & "; Snippet=" & Left(CStr(responseData.Item("body")), 160) + + Call ASPUnit.Ok((responseData.Item("status") = 404 And bodyContains), message) + + Set responseData = Nothing +End Function +%> diff --git a/tests/integration/TestRoutes.asp b/tests/integration/TestRoutes.asp new file mode 100644 index 0000000..56b9cc5 --- /dev/null +++ b/tests/integration/TestRoutes.asp @@ -0,0 +1,51 @@ + + + + +<% +Call ASPUnit.AddModule( _ + ASPUnit.CreateModule( _ + "Route Helper Integration Tests", _ + Array( _ + ASPUnit.CreateTest("RouteHelperReadsCacheBustingSettingFromConfig"), _ + ASPUnit.CreateTest("UrlToBuildsLowercaseControllerActionPath"), _ + ASPUnit.CreateTest("AssetUrlCanOverrideCacheBustingPerCall") _ + ), _ + ASPUnit.CreateLifeCycle("SetupRouteHelper", "TeardownRouteHelper") _ + ) _ +) + +Call ASPUnit.Run() + +Sub SetupRouteHelper() + Call ResetTestRuntime() + On Error Resume Next + Set Route_Helper__Singleton = Nothing + On Error GoTo 0 +End Sub + +Sub TeardownRouteHelper() + On Error Resume Next + Set Route_Helper__Singleton = Nothing + On Error GoTo 0 + Call ResetTestRuntime() +End Sub + +Function RouteHelperReadsCacheBustingSettingFromConfig() + Call ASPUnit.Ok((Not Routes().CacheBustingEnabled), "Routes helper should read disabled cache-busting from tests/web.config") +End Function + +Function UrlToBuildsLowercaseControllerActionPath() + Dim url + url = Routes().UrlTo("HomeController", "Index", Array("id", "7")) + + Call ASPUnit.Ok((InStr(LCase(url), "/homecontroller/index?id=7") > 0), "UrlTo should build a lowercase controller/action path with query parameters") +End Function + +Function AssetUrlCanOverrideCacheBustingPerCall() + Dim url + url = Routes().AssetUrl("css/site.css", True) + + Call ASPUnit.Ok((InStr(url, "css/site.css?v=") > 0), "AssetUrl should append the configured cache-bust parameter when override is true") +End Function +%> diff --git a/tests/integration/web.config b/tests/integration/web.config index ed300d3..3bf406c 100644 --- a/tests/integration/web.config +++ b/tests/integration/web.config @@ -2,9 +2,11 @@ + + diff --git a/tests/support/HttpCaptureHelpers.asp b/tests/support/HttpCaptureHelpers.asp new file mode 100644 index 0000000..6140c30 --- /dev/null +++ b/tests/support/HttpCaptureHelpers.asp @@ -0,0 +1,48 @@ +<% +Function BuildRequestOrigin() + Dim protocol + + protocol = "http://" + If LCase(Request.ServerVariables("HTTPS")) = "on" Then + protocol = "https://" + End If + + BuildRequestOrigin = protocol & Request.ServerVariables("HTTP_HOST") +End Function + +Function GetProductionBaseUrl() + Dim configuredUrl + + configuredUrl = GetAppSetting("ProductionAppBaseUrl") + If configuredUrl = "nothing" Or Len(Trim(configuredUrl)) = 0 Then + GetProductionBaseUrl = BuildRequestOrigin() & "/" + Else + If Right(configuredUrl, 1) <> "/" Then + configuredUrl = configuredUrl & "/" + End If + GetProductionBaseUrl = configuredUrl + End If +End Function + +Function FetchPage(path) + Dim http, result, targetUrl + + targetUrl = GetProductionBaseUrl() + If Left(path, 1) = "/" Then + path = Mid(path, 2) + End If + targetUrl = targetUrl & path + + Set http = Server.CreateObject("MSXML2.ServerXMLHTTP.6.0") + http.Open "GET", targetUrl, False + http.Send + + Set result = Server.CreateObject("Scripting.Dictionary") + result.Add "url", targetUrl + result.Add "status", http.Status + result.Add "body", http.responseText + + Set FetchPage = result + Set http = Nothing +End Function +%> diff --git a/tests/test-manifest.asp b/tests/test-manifest.asp index 3e4f1f7..dd70a75 100644 --- a/tests/test-manifest.asp +++ b/tests/test-manifest.asp @@ -4,7 +4,10 @@ Sub RegisterTestPages() "unit/TestHelpers.asp", _ "unit/TestControllerRegistry.asp", _ "component/TestHomeController.asp", _ - "integration/TestMvcDispatch.asp" _ + "integration/TestMvcDispatch.asp", _ + "integration/TestRoutes.asp", _ + "integration/TestConfigSettings.asp", _ + "integration/TestRenderedOutput.asp" _ )) End Sub %> diff --git a/tests/unit/web.config b/tests/unit/web.config index ed300d3..3bf406c 100644 --- a/tests/unit/web.config +++ b/tests/unit/web.config @@ -2,9 +2,11 @@ + + diff --git a/tests/web.config b/tests/web.config index ed300d3..3bf406c 100644 --- a/tests/web.config +++ b/tests/web.config @@ -2,9 +2,11 @@ + +