diff --git a/src/index.spec.ts b/src/index.spec.ts index fc9d548..cac7126 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -189,4 +189,244 @@ describe('gulpTateru', () => { expect(error).toBeInstanceOf(PluginError); expect((error as PluginError).message).toContain('Streaming not supported'); }); + + it('should handle null files by passing them through', async () => { + const stream = gulpTateruCli(); + const nullFile = new Vinyl({ + path: 'test.json', + contents: null, + }); + + const result = await new Promise((resolve) => { + stream.once('data', resolve); + stream.write(nullFile); + stream.end(); + }); + + expect(result).toBe(nullFile); + }); + + it('should handle errors from core function', async () => { + const stream = gulpTateruCli(); + + // Create a config that will cause core() to fail + // Using an invalid cwd path should cause an error in core + const invalidConfigFile = new Vinyl({ + path: 'test-config.json', + cwd: '/absolutely/nonexistent/path/that/should/cause/error', + base: '/test', + contents: Buffer.from( + JSON.stringify({ + // Valid JSON structure but invalid paths/config for tateru-cli core + environments: { + dev: { minify: false }, + }, + translations: {}, + pages: { + test: { + template: 'nonexistent.html.twig', + output: 'test.html', + }, + }, + }) + ), + }); + + const errorPromise = new Promise((resolve) => { + stream.once('error', resolve); + }); + + stream.write(invalidConfigFile); + stream.end(); + + const error = await errorPromise; + + expect(error).toBeInstanceOf(PluginError); + expect((error as PluginError).plugin).toBe('gulp-tateru-cli'); + }); + + it('should work with env option independently', async () => { + const { count } = await new Promise<{ + count: number; + }>((resolve) => { + let n = 0; + + gulp + .src('./tateru.config.json', { cwd: 'test/fixtures' }) + .pipe(gulpTateruCli({ env: 'dev' })) + .on('data', () => { + n++; + }) + .on('end', () => { + resolve({ count: n }); + }); + }); + + expect(count).toBe(6); + }); + + it('should apply both formatter and minify functions together', async () => { + const formatter: Formatter = async (contents, fileType) => + `FORMATTED (${fileType}): ${contents}`; + const minify: Minify = async (contents) => contents.replace(/\s+/g, ' '); + + const { generatedFile } = await new Promise<{ + generatedFile: string; + }>((resolve) => { + let generatedFile: string; + + gulp + .src('./tateru.config.json', { cwd: 'test/fixtures' }) + .pipe( + gulpTateruCli({ + formatter, + minify, + page: 'about', + env: 'prod', + }) + ) + .on('data', (file) => { + generatedFile = file.contents.toString(); + }) + .on('end', () => { + resolve({ generatedFile }); + }); + }); + + expect(generatedFile).toContain('FORMATTED (html):'); + expect(generatedFile).not.toMatch(/\s{2,}/); // No multiple spaces + }); + + it('should handle different file types correctly', async () => { + const formatterCalls: { contents: string; fileType: string }[] = []; + const formatter: Formatter = async (contents, fileType) => { + formatterCalls.push({ contents, fileType: fileType ?? 'unknown' }); + return Promise.resolve(contents); + }; + + await new Promise((resolve) => { + gulp + .src('./tateru.config.json', { cwd: 'test/fixtures' }) + .pipe(gulpTateruCli({ formatter })) + .on('data', () => { + // Just collect files + }) + .on('end', () => { + resolve(); + }); + }); + + const fileTypes = formatterCalls.map((call) => call.fileType); + expect(fileTypes).toContain('html'); + expect(fileTypes).toContain('txt'); + expect(fileTypes).toContain('xml'); + expect(fileTypes).toContain('webmanifest'); + }); + + it('should set correct vinyl file properties', async () => { + const files: Vinyl[] = []; + + await new Promise((resolve) => { + gulp + .src('./tateru.config.json', { cwd: 'test/fixtures' }) + .pipe(gulpTateruCli({ page: 'about' })) + .on('data', (file) => { + files.push(file); + }) + .on('end', () => { + resolve(); + }); + }); + + expect(files).toHaveLength(1); + const file = files[0]; + + expect(file).toBeInstanceOf(Vinyl); + expect(file.contents).toBeInstanceOf(Buffer); + expect(file.path).toBeTruthy(); + expect(file.base).toBeTruthy(); + expect(file.cwd).toBeTruthy(); + }); + + it('should handle nonexistent page gracefully', async () => { + const { count } = await new Promise<{ + count: number; + }>((resolve) => { + let n = 0; + + gulp + .src('./tateru.config.json', { cwd: 'test/fixtures' }) + .pipe(gulpTateruCli({ page: 'nonexistent-page' })) + .on('data', () => { + n++; + }) + .on('end', () => { + resolve({ count: n }); + }); + }); + + // Should generate 0 files for nonexistent page + expect(count).toBe(0); + }); + + it('should handle nonexistent language gracefully', async () => { + const { count } = await new Promise<{ + count: number; + }>((resolve) => { + let n = 0; + + gulp + .src('./tateru.config.json', { cwd: 'test/fixtures' }) + .pipe(gulpTateruCli({ lang: 'nonexistent-lang' })) + .on('data', () => { + n++; + }) + .on('end', () => { + resolve({ count: n }); + }); + }); + + // Should generate 0 files for nonexistent language + expect(count).toBe(0); + }); + + it('should handle async formatter and minify functions', async () => { + const formatter: Formatter = async (contents) => { + // Simulate async operation + await new Promise((resolve) => setTimeout(resolve, 1)); + return `ASYNC_FORMATTED: ${contents}`; + }; + + const minify: Minify = async (contents) => { + // Simulate async operation + await new Promise((resolve) => setTimeout(resolve, 1)); + return contents.replace(/\s+/g, ''); + }; + + const { generatedFile } = await new Promise<{ + generatedFile: string; + }>((resolve) => { + let generatedFile: string; + + gulp + .src('./tateru.config.json', { cwd: 'test/fixtures' }) + .pipe( + gulpTateruCli({ + formatter, + minify, + page: 'about', + env: 'prod', + }) + ) + .on('data', (file) => { + generatedFile = file.contents.toString(); + }) + .on('end', () => { + resolve({ generatedFile }); + }); + }); + + expect(generatedFile).toContain('ASYNC_FORMATTED:'); + expect(generatedFile).not.toMatch(/\s+/); + }); });