234 attempt to fix js error Uncaught SyntaxError: Unexpected identifier 'hidden'

This commit is contained in:
2026-04-27 17:57:24 +03:00
parent 8a32a0d5f0
commit 74c073bd7e
149 changed files with 14361 additions and 8886 deletions
@@ -0,0 +1,228 @@
component extends="testbox.system.BaseSpec" {
function beforeAll() {
// Save existing application context so we can restore it after
if (structKeyExists(application, "_taffy")) {
variables.savedTaffy = duplicate(application._taffy);
}
// Create a fresh API instance and bootstrap it to populate application._taffy with defaults
variables.api = new core.api();
variables.api.onApplicationStart();
variables.settings = application._taffy.settings;
}
function afterAll() {
// Restore original application context
if (structKeyExists(variables, "savedTaffy")) {
application._taffy = variables.savedTaffy;
}
}
function run() {
describe("Configuration", function() {
describe("Default settings", function() {
it("should have reloadKey default of 'reload'", function() {
expect(settings.reloadKey).toBe("reload");
});
it("should have reloadPassword default of 'true'", function() {
expect(settings.reloadPassword).toBe("true");
});
it("should have reloadOnEveryRequest default of false", function() {
expect(settings.reloadOnEveryRequest).toBeFalse();
});
it("should have disableDashboard default of false", function() {
expect(settings.disableDashboard).toBeFalse();
});
it("should have disabledDashboardRedirect default of empty string", function() {
expect(settings.disabledDashboardRedirect).toBe("");
});
it("should have showDocsWhenDashboardDisabled default of false", function() {
expect(settings.showDocsWhenDashboardDisabled).toBeFalse();
});
it("should have returnExceptionsAsJson default of false", function() {
expect(settings.returnExceptionsAsJson).toBeFalse();
});
it("should have exposeTaffyHeaders default of true", function() {
expect(settings.exposeTaffyHeaders).toBeTrue();
});
it("should have allowCrossDomain default of false", function() {
expect(settings.allowCrossDomain).toBeFalse();
});
it("should have useEtags default of false", function() {
expect(settings.useEtags).toBeFalse();
});
it("should have jsonp default of false", function() {
expect(settings.jsonp).toBeFalse();
});
it("should have noDataSends204NoContent default of false", function() {
expect(settings.noDataSends204NoContent).toBeFalse();
});
it("should have endpointURLParam default of 'endpoint'", function() {
expect(settings.endpointURLParam).toBe("endpoint");
});
it("should have debugKey default of 'debug'", function() {
expect(settings.debugKey).toBe("debug");
});
it("should have unhandledPaths default of '/flex2gateway'", function() {
expect(settings.unhandledPaths).toBe("/flex2gateway");
});
it("should have globalHeaders default to empty struct", function() {
expect(settings.globalHeaders).toBeStruct();
expect(structIsEmpty(settings.globalHeaders)).toBeTrue();
});
it("should have exceptionLogAdapter default of LogToDevNull", function() {
expect(settings.exceptionLogAdapter).toBe("taffy.bonus.LogToDevNull");
});
it("should have allowGoogleFonts default of true", function() {
expect(settings.allowGoogleFonts).toBeTrue();
});
});
describe("Serializer configuration", function() {
it("should use nativeJsonSerializer by default", function() {
expect(settings.serializer).toBe("taffy.core.nativeJsonSerializer");
});
it("should have nativeJsonSerializer extend baseSerializer", function() {
var serializer = new core.nativeJsonSerializer();
expect(new tests.helpers.MetadataHelper().extendsClass(serializer, "baseSerializer")).toBeTrue();
});
});
describe("Deserializer configuration", function() {
it("should use nativeJsonDeserializer by default", function() {
expect(settings.deserializer).toBe("taffy.core.nativeJsonDeserializer");
});
it("should have nativeJsonDeserializer extend baseDeserializer", function() {
var deserializer = new core.nativeJsonDeserializer();
expect(new tests.helpers.MetadataHelper().extendsClass(deserializer, "baseDeserializer")).toBeTrue();
});
it("should support JSON content type via getFromJson", function() {
var deserializer = new core.nativeJsonDeserializer();
var meta = getMetadata(deserializer);
var hasJsonSupport = false;
for (var func in meta.functions) {
if (func.name == "getFromJson") {
hasJsonSupport = true;
break;
}
}
expect(hasJsonSupport).toBeTrue();
});
it("should support form-urlencoded content type via getFromForm", function() {
var deserializer = new core.baseDeserializer();
var meta = getMetadata(deserializer);
var hasFormSupport = false;
for (var func in meta.functions) {
if (func.name == "getFromForm") {
hasFormSupport = true;
break;
}
}
expect(hasFormSupport).toBeTrue();
});
});
describe("MIME type configuration", function() {
it("should detect mime types from serializer metadata", function() {
var serializer = new core.nativeJsonSerializer();
var meta = getMetadata(serializer);
var jsonMime = "";
for (var func in meta.functions) {
if (func.name == "getAsJson") {
if (structKeyExists(func, "taffy:mime")) {
jsonMime = func["taffy:mime"];
} else if (structKeyExists(func, "taffy_mime")) {
jsonMime = func["taffy_mime"];
}
break;
}
}
expect(jsonMime).toInclude("application/json");
});
it("should identify default mime type from serializer", function() {
var serializer = new core.nativeJsonSerializer();
var meta = getMetadata(serializer);
var isDefault = false;
for (var func in meta.functions) {
if (func.name == "getAsJson") {
if (structKeyExists(func, "taffy:default")) {
isDefault = func["taffy:default"];
} else if (structKeyExists(func, "taffy_default")) {
isDefault = func["taffy_default"];
}
break;
}
}
expect(isDefault).toBeTrue();
});
});
describe("Version", function() {
it("should report version 4.0.0", function() {
expect(application._taffy.version).toBe("4.0.0");
});
});
describe("Unhandled paths regex", function() {
it("should convert unhandledPaths to regex", function() {
expect(structKeyExists(settings, "unhandledPathsRegex")).toBeTrue();
expect(len(settings.unhandledPathsRegex)).toBeGT(0);
});
it("should match the default /flex2gateway path", function() {
expect(reFindNoCase("^(" & settings.unhandledPathsRegex & ")", "/flex2gateway")).toBeGT(0);
});
});
describe("Content types", function() {
it("should have registered supported content types", function() {
expect(structKeyExists(application._taffy, "contentTypes")).toBeTrue();
expect(application._taffy.contentTypes).toBeStruct();
});
});
});
}
}
@@ -0,0 +1,220 @@
component extends="testbox.system.BaseSpec" {
function beforeAll() {
// Initialize application scope with minimal settings required by resource.cfc
application._taffy = {
settings: {
serializer: "core.nativeJsonSerializer",
noDataSends204NoContent: false
},
factory: new core.factory(),
compat: {
queryToArray: "missing",
queryToStruct: "missing"
}
};
}
function run() {
describe("HTTP Methods", function() {
describe("Standard HTTP verb mapping", function() {
it("should recognize GET method in resource", function() {
var resource = new tests.resources.MockSimpleResource();
var meta = getMetadata(resource);
var hasGet = false;
for (var func in meta.functions) {
if (func.name == "get") {
hasGet = true;
break;
}
}
expect(hasGet).toBeTrue();
});
it("should recognize POST method in resource", function() {
var resource = new tests.resources.MockSimpleResource();
var meta = getMetadata(resource);
var hasPost = false;
for (var func in meta.functions) {
if (func.name == "post") {
hasPost = true;
break;
}
}
expect(hasPost).toBeTrue();
});
it("should recognize PUT method in resource", function() {
var resource = new tests.resources.MockTokenResource();
var meta = getMetadata(resource);
var hasPut = false;
for (var func in meta.functions) {
if (func.name == "put") {
hasPut = true;
break;
}
}
expect(hasPut).toBeTrue();
});
it("should recognize DELETE method in resource", function() {
var resource = new tests.resources.MockTokenResource();
var meta = getMetadata(resource);
var hasDelete = false;
for (var func in meta.functions) {
if (func.name == "delete") {
hasDelete = true;
break;
}
}
expect(hasDelete).toBeTrue();
});
});
describe("taffy:verb metadata override", function() {
it("should recognize taffy:verb=PATCH on custom method", function() {
var resource = new tests.resources.MockVerbOverrideResource();
var meta = getMetadata(resource);
var patchFunc = "";
for (var func in meta.functions) {
if (func.name == "updatePartial") {
patchFunc = func;
break;
}
}
expect(patchFunc).notToBeEmpty();
var hasVerbMeta = structKeyExists(patchFunc, "taffy:verb")
|| structKeyExists(patchFunc, "taffy_verb");
expect(hasVerbMeta).toBeTrue();
var verbValue = structKeyExists(patchFunc, "taffy:verb")
? patchFunc["taffy:verb"]
: patchFunc["taffy_verb"];
expect(verbValue).toBe("PATCH");
});
it("should recognize taffy_verb (underscore style) on custom method", function() {
var resource = new tests.resources.MockVerbOverrideResource();
var meta = getMetadata(resource);
var optionsFunc = "";
for (var func in meta.functions) {
if (func.name == "handleOptions") {
optionsFunc = func;
break;
}
}
expect(optionsFunc).notToBeEmpty();
var hasVerbMeta = structKeyExists(optionsFunc, "taffy:verb")
|| structKeyExists(optionsFunc, "taffy_verb");
expect(hasVerbMeta).toBeTrue();
});
});
describe("Resource taffy:uri metadata", function() {
it("should have taffy:uri on MockSimpleResource", function() {
var resource = new tests.resources.MockSimpleResource();
var meta = getMetadata(resource);
var hasUri = structKeyExists(meta, "taffy:uri")
|| structKeyExists(meta, "taffy_uri");
expect(hasUri).toBeTrue();
});
it("should have correct URI pattern on MockTokenResource", function() {
var resource = new tests.resources.MockTokenResource();
var meta = getMetadata(resource);
var uri = structKeyExists(meta, "taffy:uri")
? meta["taffy:uri"]
: meta["taffy_uri"];
expect(uri).toBe("/items/{id}");
});
it("should have correct URI pattern on MockMultiTokenResource", function() {
var resource = new tests.resources.MockMultiTokenResource();
var meta = getMetadata(resource);
var uri = structKeyExists(meta, "taffy:uri")
? meta["taffy:uri"]
: meta["taffy_uri"];
expect(uri).toBe("/users/{userId}/orders/{orderId}");
});
});
describe("Resource inheritance", function() {
it("should extend core.resource", function() {
var resource = new tests.resources.MockSimpleResource();
expect(new tests.helpers.MetadataHelper().extendsClass(resource, "resource")).toBeTrue();
});
it("should have access to rep() method from parent", function() {
var resource = new tests.resources.MockSimpleResource();
expect(resource).toHaveKey("rep");
});
it("should have access to representationOf() method from parent", function() {
var resource = new tests.resources.MockSimpleResource();
expect(resource).toHaveKey("representationOf");
});
});
describe("Resource method invocation", function() {
it("should execute GET and return serializer", function() {
var resource = new tests.resources.MockSimpleResource();
var result = resource.get();
expect(new tests.helpers.MetadataHelper().extendsClass(result, "baseSerializer")).toBeTrue();
expect(result.getData().method).toBe("GET");
});
it("should execute POST with arguments", function() {
var resource = new tests.resources.MockSimpleResource();
var result = resource.post(name = "TestItem");
expect(new tests.helpers.MetadataHelper().extendsClass(result, "baseSerializer")).toBeTrue();
expect(result.getData().name).toBe("TestItem");
expect(result.getStatus()).toBe(201);
});
it("should execute GET with token parameter", function() {
var resource = new tests.resources.MockTokenResource();
var result = resource.get(id = "123");
expect(result.getData().id).toBe("123");
expect(result.getData().method).toBe("GET");
});
it("should execute PUT with token and body parameters", function() {
var resource = new tests.resources.MockTokenResource();
var result = resource.put(id = "456", name = "Updated");
expect(result.getData().id).toBe("456");
expect(result.getData().name).toBe("Updated");
expect(result.getData().updated).toBeTrue();
});
it("should execute DELETE with token parameter", function() {
var resource = new tests.resources.MockTokenResource();
var result = resource.delete(id = "789");
expect(result.getData().id).toBe("789");
expect(result.getData().deleted).toBeTrue();
});
it("should execute GET with multiple tokens", function() {
var resource = new tests.resources.MockMultiTokenResource();
var result = resource.get(userId = "1", orderId = "2");
expect(result.getData().userId).toBe("1");
expect(result.getData().orderId).toBe("2");
});
});
});
}
}
@@ -0,0 +1,239 @@
component extends="testbox.system.BaseSpec" {
function run() {
describe("Hooks", function() {
describe("onTaffyRequest hook", function() {
it("should be defined in api.cfc", function() {
var api = new core.api();
expect(api).toHaveKey("onTaffyRequest");
});
it("should accept required parameters", function() {
var api = new core.api();
var meta = getMetadata(api);
var hookFunc = "";
for (var func in meta.functions) {
if (func.name == "onTaffyRequest") {
hookFunc = func;
break;
}
}
expect(hookFunc).notToBeEmpty();
expect(hookFunc.parameters).toBeArray();
// Should have all expected parameters
var paramNames = [];
for (var param in hookFunc.parameters) {
arrayAppend(paramNames, param.name);
}
expect(arrayFindNoCase(paramNames, "verb")).toBeGT(0);
expect(arrayFindNoCase(paramNames, "cfc")).toBeGT(0);
expect(arrayFindNoCase(paramNames, "requestArguments")).toBeGT(0);
expect(arrayFindNoCase(paramNames, "mimeExt")).toBeGT(0);
expect(arrayFindNoCase(paramNames, "headers")).toBeGT(0);
expect(arrayFindNoCase(paramNames, "methodMetadata")).toBeGT(0);
expect(arrayFindNoCase(paramNames, "matchedURI")).toBeGT(0);
});
it("should return true by default", function() {
var api = new core.api();
var result = api.onTaffyRequest(
verb = "GET",
cfc = "testResource",
requestArguments = {},
mimeExt = "json",
headers = {},
methodMetadata = {},
matchedURI = "/test"
);
expect(result).toBeTrue();
});
});
describe("onTaffyRequestEnd hook", function() {
it("should be defined in api.cfc", function() {
var api = new core.api();
expect(api).toHaveKey("onTaffyRequestEnd");
});
it("should accept required parameters", function() {
var api = new core.api();
var meta = getMetadata(api);
var hookFunc = "";
for (var func in meta.functions) {
if (func.name == "onTaffyRequestEnd") {
hookFunc = func;
break;
}
}
expect(hookFunc).notToBeEmpty();
var paramNames = [];
for (var param in hookFunc.parameters) {
arrayAppend(paramNames, param.name);
}
// Should include response-related parameters
expect(arrayFindNoCase(paramNames, "parsedResponse")).toBeGT(0);
expect(arrayFindNoCase(paramNames, "originalResponse")).toBeGT(0);
expect(arrayFindNoCase(paramNames, "statusCode")).toBeGT(0);
});
it("should return true by default", function() {
var api = new core.api();
var result = api.onTaffyRequestEnd(
verb = "GET",
cfc = "testResource",
requestArguments = {},
mimeExt = "json",
headers = {},
methodMetadata = {},
matchedURI = "/test",
parsedResponse = '{"test":true}',
originalResponse = { test: true },
statusCode = 200
);
expect(result).toBeTrue();
});
});
describe("Caching hooks", function() {
it("should have validCacheExists hook", function() {
var api = new core.api();
expect(api).toHaveKey("validCacheExists");
});
it("validCacheExists should return false by default", function() {
var api = new core.api();
var result = api.validCacheExists(cacheKey = "test-key");
expect(result).toBeFalse();
});
it("should have setCachedResponse hook", function() {
var api = new core.api();
expect(api).toHaveKey("setCachedResponse");
});
it("should have getCachedResponse hook", function() {
var api = new core.api();
expect(api).toHaveKey("getCachedResponse");
});
it("should have getCacheKey hook", function() {
var api = new core.api();
expect(api).toHaveKey("getCacheKey");
});
it("getCacheKey should generate key from request params", function() {
var api = new core.api();
var requestArgs = { id: 123 };
var result = api.getCacheKey(
cfc = "testResource",
requestArguments = requestArgs,
matchedURI = "/items/{id}"
);
expect(result).toInclude("/items/{id}");
});
});
describe("getEnvironment hook", function() {
it("should be defined in api.cfc", function() {
var api = new core.api();
expect(api).toHaveKey("getEnvironment");
});
it("should return empty string by default", function() {
var api = new core.api();
var result = api.getEnvironment();
expect(result).toBe("");
});
});
describe("Hook extensibility", function() {
it("should allow overriding onTaffyRequest in subclass", function() {
// Any class extending core.api can override hooks
var api = new core.api();
// The base api has the hook that can be overridden
expect(api).toHaveKey("onTaffyRequest");
// Verify it's a function that can be overridden
expect(isCustomFunction(api.onTaffyRequest)).toBeTrue();
});
});
describe("Basic auth helper", function() {
it("should have getBasicAuthCredentials method", function() {
var api = new core.api();
expect(api).toHaveKey("getBasicAuthCredentials");
});
it("getBasicAuthCredentials should return struct with username and password", function() {
var api = new core.api();
var result = api.getBasicAuthCredentials();
expect(result).toBeStruct();
expect(result).toHaveKey("username");
expect(result).toHaveKey("password");
});
it("should return empty credentials when no auth header", function() {
var api = new core.api();
var result = api.getBasicAuthCredentials();
expect(result.username).toBe("");
expect(result.password).toBe("");
});
});
describe("Helper methods", function() {
it("should have getHostname helper", function() {
var api = new core.api();
expect(api).toHaveKey("getHostname");
var hostname = api.getHostname();
expect(len(hostname)).toBeGT(0);
});
it("should have addHeaders helper", function() {
var api = new core.api();
expect(api).toHaveKey("addHeaders");
});
it("should have rep helper for responses", function() {
var api = new core.api();
expect(api).toHaveKey("rep");
});
it("should have representationOf helper", function() {
var api = new core.api();
expect(api).toHaveKey("representationOf");
});
it("should have noData helper", function() {
var api = new core.api();
expect(api).toHaveKey("noData");
});
it("should have noContent helper", function() {
var api = new core.api();
expect(api).toHaveKey("noContent");
});
});
});
}
}
@@ -0,0 +1,252 @@
component extends="testbox.system.BaseSpec" {
function beforeAll() {
// Set up minimal application context
application._taffy = {
settings: {
serializer: "core.nativeJsonSerializer",
noDataSends204NoContent: false
},
factory: new core.factory(),
compat: {
queryToArray: "missing",
queryToStruct: "missing"
}
};
}
function run() {
describe("Response Handling", function() {
describe("Status codes", function() {
it("should default to 200 OK", function() {
var resource = new tests.resources.MockSimpleResource();
var result = resource.get();
expect(result.getStatus()).toBe(200);
expect(result.getStatusText()).toBe("OK");
});
it("should support 201 Created", function() {
var resource = new tests.resources.MockSimpleResource();
var result = resource.post(name = "Test");
expect(result.getStatus()).toBe(201);
expect(result.getStatusText()).toBe("Created");
});
it("should support 404 Not Found", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({ error: "Resource not found" }).withStatus(404);
expect(serializer.getStatus()).toBe(404);
expect(serializer.getStatusText()).toBe("Not Found");
});
it("should support 400 Bad Request", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({ error: "Invalid input" }).withStatus(400);
expect(serializer.getStatus()).toBe(400);
expect(serializer.getStatusText()).toBe("Bad Request");
});
it("should support 500 Internal Server Error", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({ error: "Something went wrong" }).withStatus(500);
expect(serializer.getStatus()).toBe(500);
expect(serializer.getStatusText()).toBe("Internal Server Error");
});
it("should support custom status text", function() {
var serializer = new core.nativeJsonSerializer();
serializer.withStatus(299, "Custom Success");
expect(serializer.getStatus()).toBe(299);
expect(serializer.getStatusText()).toBe("Custom Success");
});
});
describe("Response headers", function() {
it("should set custom headers", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({ id: 123 })
.withHeaders({ "X-Request-Id": "abc123" });
var headers = serializer.getHeaders();
expect(headers["X-Request-Id"]).toBe("abc123");
});
it("should set Location header for created resources", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({ id: 456 })
.withStatus(201)
.withHeaders({ "Location": "/items/456" });
expect(serializer.getHeaders()["Location"]).toBe("/items/456");
});
it("should set multiple headers", function() {
var serializer = new core.nativeJsonSerializer();
serializer.withHeaders({
"X-Rate-Limit": "100",
"X-Rate-Remaining": "99",
"X-Cache-Control": "no-cache"
});
var headers = serializer.getHeaders();
expect(headers["X-Rate-Limit"]).toBe("100");
expect(headers["X-Rate-Remaining"]).toBe("99");
expect(headers["X-Cache-Control"]).toBe("no-cache");
});
});
describe("JSON serialization", function() {
it("should serialize response data as JSON", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({ message: "Hello", count: 42 });
var json = serializer.getAsJson();
expect(isJSON(json)).toBeTrue();
var parsed = deserializeJSON(json);
expect(parsed.message).toBe("Hello");
expect(parsed.count).toBe(42);
});
it("should serialize nested structures", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({
user: {
name: "John",
email: "john@example.com"
},
permissions: ["read", "write"]
});
var json = serializer.getAsJson();
var parsed = deserializeJSON(json);
expect(parsed.user.name).toBe("John");
expect(parsed.permissions).toBeArray();
});
it("should serialize array responses", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData([
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" }
]);
var json = serializer.getAsJson();
var parsed = deserializeJSON(json);
expect(parsed).toBeArray();
expect(arrayLen(parsed)).toBe(2);
});
it("should handle boolean values correctly", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({
active: true,
deleted: false
});
var json = serializer.getAsJson();
var parsed = deserializeJSON(json);
expect(parsed.active).toBeTrue();
expect(parsed.deleted).toBeFalse();
});
});
describe("noData() and noContent()", function() {
it("noData() should return empty response when setting is false", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setNoDataSends204NoContent(false);
var result = serializer.noData();
// Should still be 200 with empty data
expect(result.getStatus()).toBe(200);
});
it("noData() should return 204 when setting is true", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setNoDataSends204NoContent(true);
var result = serializer.noData();
expect(result.getStatus()).toBe(204);
});
it("noContent() should return 204", function() {
var serializer = new core.nativeJsonSerializer();
var result = serializer.noContent();
expect(result.getStatus()).toBe(204);
expect(result.getStatusText()).toBe("No Content");
});
it("noContent() should set Content-Type to text/plain", function() {
var serializer = new core.nativeJsonSerializer();
var result = serializer.noContent();
var headers = result.getHeaders();
expect(headers["Content-Type"]).toBe("text/plain");
});
});
describe("Response type detection", function() {
it("should identify textual response type", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setData({ message: "test" });
expect(serializer.getType()).toBe("textual");
});
it("should identify filename response type", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setFileName("/path/to/file.pdf");
expect(serializer.getType()).toBe("filename");
});
it("should identify filedata response type", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setFileData(toBinary(toBase64("test data")));
expect(serializer.getType()).toBe("filedata");
});
it("should identify imagedata response type", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setImageData(toBinary(toBase64("image data")));
expect(serializer.getType()).toBe("imagedata");
});
});
describe("File streaming responses", function() {
it("should configure file download response", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setFileName("/path/to/report.pdf")
.withMime("application/pdf");
expect(serializer.getFileName()).toBe("/path/to/report.pdf");
expect(serializer.getFileMime()).toBe("application/pdf");
expect(serializer.getType()).toBe("filename");
});
it("should configure binary data response", function() {
var binaryData = toBinary(toBase64("PDF content here"));
var serializer = new core.nativeJsonSerializer();
serializer.setFileData(binaryData)
.withMime("application/pdf");
expect(serializer.getFileData()).toBe(binaryData);
expect(serializer.getFileMime()).toBe("application/pdf");
});
it("should configure file delete after download", function() {
var serializer = new core.nativeJsonSerializer();
serializer.setFileName("/tmp/temp-report.pdf")
.withMime("application/pdf")
.andDelete(true);
expect(serializer.getDeleteFile()).toBeTrue();
});
});
});
}
}
@@ -0,0 +1,169 @@
component extends="testbox.system.BaseSpec" {
function beforeAll() {
// Initialize application scope with minimal settings required by resource.cfc
application._taffy = {
settings: {
serializer: "core.nativeJsonSerializer",
noDataSends204NoContent: false
},
factory: new core.factory(),
compat: {
queryToArray: "missing",
queryToStruct: "missing"
}
};
// Create a mock API instance for testing URI methods
variables.api = new core.api();
}
function run() {
describe("URI Matching", function() {
describe("convertURItoRegex()", function() {
it("should convert simple static URI to regex", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/users");
expect(result).toBeStruct();
expect(result).toHaveKey("uriRegex");
expect(result).toHaveKey("tokens");
expect(result.tokens).toBeArray();
expect(arrayLen(result.tokens)).toBe(0);
});
it("should extract single token from URI", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/users/{id}");
expect(arrayLen(result.tokens)).toBe(1);
expect(result.tokens[1]).toBe("id");
});
it("should extract multiple tokens from URI", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/users/{userId}/orders/{orderId}");
expect(arrayLen(result.tokens)).toBe(2);
expect(result.tokens[1]).toBe("userId");
expect(result.tokens[2]).toBe("orderId");
});
it("should handle mixed static and token segments", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/api/v1/users/{id}/profile");
expect(arrayLen(result.tokens)).toBe(1);
expect(result.tokens[1]).toBe("id");
});
it("should generate regex that matches expected URIs", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/items/{id}");
var regex = result.uriRegex;
// Should match /items/123
expect(reFindNoCase(regex, "/items/123")).toBeGT(0);
// Should match /items/abc
expect(reFindNoCase(regex, "/items/abc")).toBeGT(0);
// Should match with format extension
expect(reFindNoCase(regex, "/items/123.json")).toBeGT(0);
});
it("should support custom regex patterns in tokens", function() {
// Taffy supports {tokenName:regex} syntax
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/users/{id:[0-9]+}");
expect(result.tokens[1]).toBe("id");
// The regex should only match numeric IDs
var regex = result.uriRegex;
expect(reFindNoCase(regex, "/users/123")).toBeGT(0);
});
});
describe("URI regex matching", function() {
it("should match exact static path", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/simple");
expect(reFindNoCase(result.uriRegex, "/simple")).toBeGT(0);
});
it("should match path with trailing slash", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/simple");
expect(reFindNoCase(result.uriRegex, "/simple/")).toBeGT(0);
});
it("should match path with format extension", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/items/{id}");
expect(reFindNoCase(result.uriRegex, "/items/123.json")).toBeGT(0);
expect(reFindNoCase(result.uriRegex, "/items/abc.xml")).toBeGT(0);
});
it("should not match unrelated paths", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/users/{id}");
expect(reFindNoCase(result.uriRegex, "/items/123")).toBe(0);
});
it("should handle deeply nested URIs", function() {
var result = makePublic(api, "convertURItoRegex").convertURItoRegex("/api/v1/users/{userId}/orders/{orderId}/items/{itemId}");
expect(arrayLen(result.tokens)).toBe(3);
expect(reFindNoCase(result.uriRegex, "/api/v1/users/1/orders/2/items/3")).toBeGT(0);
});
});
describe("Token value extraction", function() {
it("should extract token values from matched URI", function() {
var uriConfig = makePublic(api, "convertURItoRegex").convertURItoRegex("/users/{id}");
var matchResult = reFindNoSuck(uriConfig.uriRegex, "/users/123");
expect(matchResult).toBeArray();
expect(arrayLen(matchResult)).toBeGTE(1);
expect(matchResult[1]).toBe("123");
});
it("should extract multiple token values", function() {
var uriConfig = makePublic(api, "convertURItoRegex").convertURItoRegex("/users/{userId}/orders/{orderId}");
var matchResult = reFindNoSuck(uriConfig.uriRegex, "/users/42/orders/99");
expect(arrayLen(matchResult)).toBeGTE(2);
expect(matchResult[1]).toBe("42");
expect(matchResult[2]).toBe("99");
});
});
describe("sortURIMatchOrder()", function() {
it("should sort URIs for proper matching order", function() {
var endpoints = {
"^/users/([^\/]+)": { srcUri: "/users/{id}" },
"^/users": { srcUri: "/users" },
"^/users/([^\/]+)/profile": { srcUri: "/users/{id}/profile" }
};
var result = makePublic(api, "sortURIMatchOrder").sortURIMatchOrder(endpoints);
expect(result).toBeArray();
// More specific patterns should be sorted appropriately
expect(arrayLen(result)).toBe(3);
});
});
});
}
/**
* Reimplementation of reFindNoSuck for testing
*/
private function reFindNoSuck(required string pattern, required string data, numeric startPos = 1) {
var local = {};
local.awesome = [];
local.sucky = reFindNoCase(arguments.pattern, arguments.data, arguments.startPos, true);
if (!isArray(local.sucky.len) || arrayLen(local.sucky.len) == 0) {
return [];
}
for (local.i = 1; local.i <= arrayLen(local.sucky.len); local.i++) {
if (local.sucky.len[local.i] > 0 && local.sucky.pos[local.i] > 0) {
local.matchBody = mid(arguments.data, local.sucky.pos[local.i], local.sucky.len[local.i]);
if (local.matchBody != arguments.data) {
arrayAppend(local.awesome, local.matchBody);
}
}
}
return local.awesome;
}
}