|
1 | 1 | const assert = require('assert'); |
2 | 2 | const libfs = require('fs'); |
| 3 | +const libpath = require('path'); |
3 | 4 |
|
4 | 5 | let post_pledge; |
5 | 6 |
|
@@ -74,6 +75,83 @@ describe('Controller', function() { |
74 | 75 | await testFormSubmission(post_pledge, 'addfiles'); |
75 | 76 | }); |
76 | 77 | }); |
| 78 | + |
| 79 | + describe('#serveFile', function() { |
| 80 | + |
| 81 | + let serve_file_pledge; |
| 82 | + |
| 83 | + before(() => { |
| 84 | + Router.add({ |
| 85 | + name : 'ConduitTest#serveFileTest', |
| 86 | + paths : '/conduit/serve_file_test', |
| 87 | + methods : 'get', |
| 88 | + }); |
| 89 | + |
| 90 | + ConduitTestController.setAction(async function serveFileTest(conduit) { |
| 91 | + let use_on_error = conduit.param('use_on_error') === 'true'; |
| 92 | + let file_path = conduit.param('file_path'); |
| 93 | + |
| 94 | + // Create an Inode.File instance |
| 95 | + let file = new Classes.Alchemy.Inode.File(file_path); |
| 96 | + |
| 97 | + let options = {}; |
| 98 | + |
| 99 | + if (use_on_error) { |
| 100 | + options.onError = (err) => { |
| 101 | + // Custom error handling: return a JSON response with error info |
| 102 | + conduit.setHeader('content-type', 'application/json'); |
| 103 | + conduit.end(JSON.stringify({ |
| 104 | + custom_error: true, |
| 105 | + error_code: err.code, |
| 106 | + error_message: err.message |
| 107 | + })); |
| 108 | + }; |
| 109 | + } |
| 110 | + |
| 111 | + return conduit.serveFile(file, options); |
| 112 | + }); |
| 113 | + }); |
| 114 | + |
| 115 | + it('should call onError callback when serving a non-existent File object', async function() { |
| 116 | + |
| 117 | + let non_existent_path = libpath.resolve(__dirname, 'does_not_exist_' + Date.now() + '.txt'); |
| 118 | + let url = global.getRouteUrl('ConduitTest#serveFileTest'); |
| 119 | + url += '?use_on_error=true&file_path=' + encodeURIComponent(non_existent_path); |
| 120 | + |
| 121 | + let { response, body } = await harness.fetch(url); |
| 122 | + |
| 123 | + // The onError callback should have been called, returning a JSON response |
| 124 | + // instead of the default 404 notFound behavior |
| 125 | + assert.strictEqual(response.statusCode, 200, 'Should return 200 because onError handled it'); |
| 126 | + |
| 127 | + // Body may already be parsed as JSON by Blast.fetch |
| 128 | + let parsed = typeof body === 'string' ? JSON.parse(body) : body; |
| 129 | + assert.strictEqual(parsed.custom_error, true, 'Should have custom_error flag'); |
| 130 | + assert.strictEqual(parsed.error_code, 'ENOENT', 'Should have ENOENT error code'); |
| 131 | + }); |
| 132 | + |
| 133 | + it('should call notFound when onError is not provided for non-existent File', async function() { |
| 134 | + |
| 135 | + let non_existent_path = libpath.resolve(__dirname, 'does_not_exist_' + Date.now() + '.txt'); |
| 136 | + let url = global.getRouteUrl('ConduitTest#serveFileTest'); |
| 137 | + url += '?use_on_error=false&file_path=' + encodeURIComponent(non_existent_path); |
| 138 | + |
| 139 | + // Without onError, notFound should be called, returning 404 |
| 140 | + // Blast.fetch throws on 4xx/5xx status codes, so we need to catch the error |
| 141 | + let threw = false; |
| 142 | + let errorNumber; |
| 143 | + |
| 144 | + try { |
| 145 | + await harness.fetch(url); |
| 146 | + } catch (err) { |
| 147 | + threw = true; |
| 148 | + errorNumber = err.number; |
| 149 | + } |
| 150 | + |
| 151 | + assert.strictEqual(threw, true, 'Should throw an error for 404'); |
| 152 | + assert.strictEqual(errorNumber, 404, 'Should return 404 when file not found and no onError'); |
| 153 | + }); |
| 154 | + }); |
77 | 155 | }); |
78 | 156 |
|
79 | 157 | async function testFormSubmission(post_pledge, enctype) { |
|
0 commit comments