Skip to content
Closed
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
53 changes: 53 additions & 0 deletions interceptors/CBWIRE.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,65 @@ component {

function postLayoutRender() {
if ( shouldInject( arguments.event ) && !request.keyExists( "_cbwire_injected_assets" ) ) {
// Get the layout file content to check for required tags
local.layoutContent = getLayoutContent( arguments.event );

// Check if the layout has required tags for asset injection
if ( !findNoCase( "</head>", local.layoutContent ) ) {
throw(
type = "CBWIREException",
message = "Layout is missing </head> tag required for wireStyles() injection.",
detail = "Your layout must include a </head> tag where CBWIRE can inject CSS styles. Either add a </head> tag to your layout or set 'autoInjectAssets' to false and manually call wireStyles() and wireScripts()."
);
}
if ( !findNoCase( "</body>", local.layoutContent ) ) {
throw(
type = "CBWIREException",
message = "Layout is missing </body> tag required for wireScripts() injection.",
detail = "Your layout must include a </body> tag where CBWIRE can inject JavaScript. Either add a </body> tag to your layout or set 'autoInjectAssets' to false and manually call wireStyles() and wireScripts()."
);
}

arguments.data.renderedLayout = replaceNoCase( arguments.data.renderedLayout, "</head>", getStyles() & chr( 10 ) & "</head>", "one" );
arguments.data.renderedLayout = replaceNoCase( arguments.data.renderedLayout, "</body>", getScripts() & chr( 10 ) & "</body>", "one" );
request._cbwire_injected_assets = true;
}
}

/**
* Gets the layout file content for validation.
* Reads the actual layout file from disk based on the current layout name.
*
* @event The request context object
*
* @return string The layout file content
*/
private function getLayoutContent( event ) {
// Get the current layout name from the private collection
local.layoutName = arguments.event.getPrivateValue( "currentLayout", "" );

if ( !len( local.layoutName ) ) {
return "";
}

// Get the layouts directory path
local.layoutsPath = expandPath( "/layouts/" );

// Try common file extensions
local.extensions = [ ".cfm", ".bxm" ];

for ( local.ext in local.extensions ) {
local.layoutFile = local.layoutsPath & local.layoutName & local.ext;
if ( fileExists( local.layoutFile ) ) {
return fileRead( local.layoutFile );
}
}

// If we can't find the layout file, return empty string
// This will allow the existing rendered content check to fail gracefully
return "";
}

function preModuleLoad() eventPattern="^cbwire.*" {
return true;
}
Expand Down
21 changes: 21 additions & 0 deletions test-harness/handlers/Tests.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Handler for testing missing layout tags
*/
component {

function testMissingHeadTag( event, rc, prc ) {
event.setLayout( "MissingHeadTag" );
event.setView( "tests/missingtags" );
}

function testMissingBodyTag( event, rc, prc ) {
event.setLayout( "MissingBodyTag" );
event.setView( "tests/missingtags" );
}

function testMissingBothTags( event, rc, prc ) {
event.setLayout( "MissingBothTags" );
event.setView( "tests/missingtags" );
}

}
9 changes: 9 additions & 0 deletions test-harness/layouts/MissingBodyTag.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<cfoutput>
<!doctype html>
<html>
<head>
<title>Missing Body Tag</title>
</head>
#view()#
</html>
</cfoutput>
6 changes: 6 additions & 0 deletions test-harness/layouts/MissingBothTags.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<cfoutput>
<!doctype html>
<html>
#view()#
</html>
</cfoutput>
8 changes: 8 additions & 0 deletions test-harness/layouts/MissingHeadTag.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<cfoutput>
<!doctype html>
<html>
<body>
#view()#
</body>
</html>
</cfoutput>
27 changes: 27 additions & 0 deletions test-harness/tests/specs/CBWIRESpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,33 @@ component extends="coldbox.system.testing.BaseTestCase" {
expect( beforeHead ).toInclude( "<link rel=""stylesheet"" href=""https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"">" );
} );

it( "should throw exception when layout is missing </head> tag with autoInjectAssets enabled", function() {
var settings = getInstance( "coldbox:modulesettings:cbwire" );
settings.autoInjectAssets = true;
expect( function() {
this.get( "tests.testMissingHeadTag" );
} ).toThrow( type="CBWIREException", message="Layout is missing </head> tag required for wireStyles() injection." );
} );

it( "should throw exception when layout is missing </body> tag with autoInjectAssets enabled", function() {
var settings = getInstance( "coldbox:modulesettings:cbwire" );
settings.autoInjectAssets = true;
expect( function() {
this.get( "tests.testMissingBodyTag" );
} ).toThrow( type="CBWIREException", message="Layout is missing </body> tag required for wireScripts() injection." );
} );

it( "should not throw exception when layout is missing tags with autoInjectAssets disabled", function() {
var settings = getInstance( "coldbox:modulesettings:cbwire" );
settings.autoInjectAssets = false;
var event = this.get( "tests.testMissingBothTags" );
var html = event.getRenderedContent();
// Should render without error
expect( html ).toBeString();
expect( html ).notToInclude( "<!-- CBWIRE Styles -->" );
expect( html ).notToInclude( "<!-- CBWIRE Scripts -->" );
} );

} );

describe("Component.cfc", function() {
Expand Down
9 changes: 5 additions & 4 deletions test-harness/tests/specs/FileUploadSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,15 @@ component extends="coldbox.system.testing.BaseTestCase" {
var result = loadMockedFileUpload( "test-store-file", "text", "plain" );
var destinationDir = getTempDirectory() & "/cbwire-test-store-file";
var destinationPath = destinationDir & "/myfile.png";

// Store the file with specific filename
var storedPath = result.store( destinationPath );

// Verify the file was moved to the destination with the new name
expect( fileExists( storedPath ) ).toBeTrue();
expect( storedPath ).toBe( getCanonicalPath( destinationPath ) );

// Normalize both paths to handle platform differences (e.g., /var vs /private/var on macOS)
expect( getCanonicalPath( storedPath ) ).toBe( getCanonicalPath( destinationPath ) );

// Clean up
if ( directoryExists( destinationDir ) ) {
directoryDelete( destinationDir, true );
Expand Down
3 changes: 3 additions & 0 deletions test-harness/views/tests/missingtags.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<cfoutput>
#wire( "Counter" )#
</cfoutput>
Loading