From 789f1239268a4f60ada6124596cd44c4f42e1d31 Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Mon, 5 May 2025 13:18:24 +0100 Subject: [PATCH] Improve test App `requestJob` Detect if provided params are a subset of actual params, provide informative errors if not. --- build.zig.zon | 4 +- demo/src/app/views/background_jobs.zig | 8 ++++ src/compile_static_routes.zig | 5 ++- src/jetzig/http/Request.zig | 1 + src/jetzig/http/Server.zig | 4 ++ src/jetzig/mail/Job.zig | 4 +- src/jetzig/testing.zig | 53 +++++++++++++++++++++++--- src/jetzig/testing/App.zig | 1 + 8 files changed, 68 insertions(+), 12 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 84e284c..d60085c 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -25,8 +25,8 @@ .hash = "jetkv-0.0.0-zCv0fmCGAgCyYqwHjk0P5KrYVRew1MJAtbtAcIO-WPpT", }, .zmpl = .{ - .url = "https://github.com/jetzig-framework/zmpl/archive/c57fc9b83027e8c1459d9625c3509f59f0fb89f3.tar.gz", - .hash = "zmpl-0.0.1-SYFGBgdqAwDeA6xm4KAhpKoNrWs5CMQK6x447zhWclCs", + .url = "https://github.com/jetzig-framework/zmpl/archive/03cc97b52e80ac368f0dfe2e19c2b3dcdbf9f6ed.tar.gz", + .hash = "zmpl-0.0.1-SYFGBsSZAwBaIVdcokCVyM2azwVO3OTfaTTPddWERpyq", }, .httpz = .{ .url = "https://github.com/karlseguin/http.zig/archive/37d7cb9819b804ade5f4b974b82f8dd0622225ed.tar.gz", diff --git a/demo/src/app/views/background_jobs.zig b/demo/src/app/views/background_jobs.zig index d73a53e..2d594ce 100644 --- a/demo/src/app/views/background_jobs.zig +++ b/demo/src/app/views/background_jobs.zig @@ -15,3 +15,11 @@ pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View { return request.render(.ok); } + +test "index" { + var app = try jetzig.testing.app(std.testing.allocator, @import("routes")); + defer app.deinit(); + + const response = try app.request(.GET, "/background_jobs", .{}); + try response.expectJob("example", .{ .foo = "bar" }); +} diff --git a/src/compile_static_routes.zig b/src/compile_static_routes.zig index 1f45ec5..b027218 100644 --- a/src/compile_static_routes.zig +++ b/src/compile_static_routes.zig @@ -147,7 +147,7 @@ fn renderMarkdown( if (zmpl.findPrefixed("views", prefixed_name)) |layout| { view.data.content = .{ .data = content }; - return try layout.render(view.data, jetzig.TemplateContext, .{}, .{}); + return try layout.render(view.data, jetzig.TemplateContext, .{}, &.{}, .{}); } else { std.debug.print("Unknown layout: {s}\n", .{layout_name}); return content; @@ -174,6 +174,7 @@ fn renderZmplTemplate( view.data, jetzig.TemplateContext, .{}, + &.{}, .{ .layout = layout }, ); } else { @@ -181,7 +182,7 @@ fn renderZmplTemplate( return try allocator.dupe(u8, ""); } } else { - return try template.render(view.data, jetzig.TemplateContext, .{}, .{}); + return try template.render(view.data, jetzig.TemplateContext, .{}, &.{}, .{}); } } else return null; } diff --git a/src/jetzig/http/Request.zig b/src/jetzig/http/Request.zig index 582706a..b49942a 100644 --- a/src/jetzig/http/Request.zig +++ b/src/jetzig/http/Request.zig @@ -307,6 +307,7 @@ pub fn renderRedirect(self: *Request, state: RedirectState) !void { self.response_data, jetzig.TemplateContext, .{ .request = self }, + &.{}, .{}, ); } else try std.fmt.allocPrint(self.allocator, "Redirecting to {s}", .{state.location}), diff --git a/src/jetzig/http/Server.zig b/src/jetzig/http/Server.zig index 9aaed47..687e929 100644 --- a/src/jetzig/http/Server.zig +++ b/src/jetzig/http/Server.zig @@ -435,6 +435,7 @@ fn renderTemplateWithLayout( view.data, jetzig.TemplateContext, template_context, + &.{}, .{ .layout = layout }, ); } else { @@ -443,6 +444,7 @@ fn renderTemplateWithLayout( view.data, jetzig.TemplateContext, template_context, + &.{}, .{}, ); } @@ -450,6 +452,7 @@ fn renderTemplateWithLayout( view.data, jetzig.TemplateContext, template_context, + &.{}, .{}, ); } @@ -613,6 +616,7 @@ fn renderErrorView( request.response_data, jetzig.TemplateContext, .{ .request = request }, + &.{}, .{}, ), }; diff --git a/src/jetzig/mail/Job.zig b/src/jetzig/mail/Job.zig index dccf828..657ed07 100644 --- a/src/jetzig/mail/Job.zig +++ b/src/jetzig/mail/Job.zig @@ -148,7 +148,7 @@ fn defaultHtml( try data.addConst("jetzig_view", data.string("")); try data.addConst("jetzig_action", data.string("")); return if (jetzig.zmpl.findPrefixed("mailers", mailer.html_template)) |template| - try template.render(&data, jetzig.TemplateContext, .{}, .{}) + try template.render(&data, jetzig.TemplateContext, .{}, &.{}, .{}) else null; } @@ -166,7 +166,7 @@ fn defaultText( try data.addConst("jetzig_view", data.string("")); try data.addConst("jetzig_action", data.string("")); return if (jetzig.zmpl.findPrefixed("mailers", mailer.text_template)) |template| - try template.render(&data, jetzig.TemplateContext, .{}, .{}) + try template.render(&data, jetzig.TemplateContext, .{}, &.{}, .{}) else null; } diff --git a/src/jetzig/testing.zig b/src/jetzig/testing.zig index 10db7d6..e6c3d9a 100644 --- a/src/jetzig/testing.zig +++ b/src/jetzig/testing.zig @@ -66,7 +66,7 @@ pub const TestResponse = struct { jobs: []Job, pub const Header = struct { name: []const u8, value: []const u8 }; - pub const Job = struct { name: []const u8, params: ?[]const u8 = null }; + pub const Job = struct { name: []const u8, params: ?*jetzig.data.Value = null }; pub fn expectStatus(self: TestResponse, comptime expected: jetzig.http.status_codes.StatusCode) !void { try testing.expectStatus(expected, self); @@ -299,13 +299,54 @@ pub fn expectJson(expected_path: []const u8, expected_value: anytype, response: } pub fn expectJob(job_name: []const u8, job_params: anytype, response: TestResponse) !void { + var actual_params_buf = std.ArrayList([]const u8).init(response.allocator); + defer actual_params_buf.deinit(); + + const value: ?*jetzig.data.Value = if (@TypeOf(job_params) == @TypeOf(null)) + null + else + try jetzig.Data.zmplValue(job_params, response.allocator); for (response.jobs) |job| { - comptime var has_args = false; - inline for (@typeInfo(@TypeOf(job_params)).Struct.fields) |field| { - has_args = true; - _ = field; + if (std.mem.eql(u8, job_name, job.name)) { + if (value != null and job.params != null) { + if (job.params.?.includes(value.?.*)) { + return; + } else { + try actual_params_buf.append(try job.params.?.toJson()); + } + } else { + return; + } } - if (!has_args and std.mem.eql(u8, job_name, job.name)) return; + } + + if (actual_params_buf.items.len == 0) { + logFailure( + "Expected job " ++ + jetzig.colors.cyan("{s}") ++ + " to have been scheduled but job was not found in the queue.", + .{job_name}, + ); + } else { + const actual_params_formatted = try std.mem.join( + response.allocator, + "\n", + actual_params_buf.items, + ); + defer response.allocator.free(actual_params_formatted); + logFailure( + "Expected params for job " ++ + jetzig.colors.cyan("{s}") ++ + ":\n" ++ + jetzig.colors.red("{s}\n") ++ + "Actual job params:\n" ++ + jetzig.colors.green("{s}"), + .{ + job_name, + if (value) |v| try v.toJson() else "null", + actual_params_formatted, + }, + ); } return error.JetzigExpectJobError; } diff --git a/src/jetzig/testing/App.zig b/src/jetzig/testing/App.zig index 98c5408..d2d6f52 100644 --- a/src/jetzig/testing/App.zig +++ b/src/jetzig/testing/App.zig @@ -208,6 +208,7 @@ pub fn request( while (try self.job_queue.popFirst(&data, "__jetzig_jobs")) |value| { if (value.getT(.string, "__jetzig_job_name")) |job_name| try jobs.append(.{ .name = try allocator.dupe(u8, job_name), + .params = value, }); }