From d806eecb81ffca4ad8caa2c596069c4ed00bb673 Mon Sep 17 00:00:00 2001 From: Daniel Sitek Date: Sun, 9 Nov 2025 16:21:37 +0100 Subject: [PATCH 1/5] Add missing tests for full coverage --- src/index.spec.ts | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/index.spec.ts b/src/index.spec.ts index fc9d548..8297508 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -189,4 +189,59 @@ 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'); + }); }); From 0094f38ee43a1ff89d6c797b4db8ae10c35636af Mon Sep 17 00:00:00 2001 From: Daniel Sitek Date: Sun, 9 Nov 2025 18:02:24 +0100 Subject: [PATCH 2/5] Add more tests for edge cases --- src/index.spec.ts | 185 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/src/index.spec.ts b/src/index.spec.ts index 8297508..d3da698 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -244,4 +244,189 @@ describe('gulpTateru', () => { 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: Array<{ contents: string; fileType: string }> = []; + const formatter: Formatter = async (contents, fileType) => { + formatterCalls.push({ contents, fileType: fileType || 'unknown' }); + return 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, fileType) => { + // 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+/); + }); }); From 90eeb9cb6f0682c8b234eb702e6638a11dce03ea Mon Sep 17 00:00:00 2001 From: Daniel Sitek Date: Sun, 9 Nov 2025 18:46:08 +0100 Subject: [PATCH 3/5] Fix code quality issues --- src/index.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index d3da698..e3919d2 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -267,7 +267,7 @@ describe('gulpTateru', () => { it('should apply both formatter and minify functions together', async () => { const formatter: Formatter = async (contents, fileType) => - `FORMATTED (${fileType}): ${contents}`; + await `FORMATTED (${fileType}): ${contents}`; const minify: Minify = async (contents) => contents.replace(/\s+/g, ' '); const { generatedFile } = await new Promise<{ @@ -298,9 +298,9 @@ describe('gulpTateru', () => { }); it('should handle different file types correctly', async () => { - const formatterCalls: Array<{ contents: string; fileType: string }> = []; + const formatterCalls: { contents: string; fileType: string }[] = []; const formatter: Formatter = async (contents, fileType) => { - formatterCalls.push({ contents, fileType: fileType || 'unknown' }); + await formatterCalls.push({ contents, fileType: fileType ?? 'unknown' }); return contents; }; @@ -391,7 +391,7 @@ describe('gulpTateru', () => { }); it('should handle async formatter and minify functions', async () => { - const formatter: Formatter = async (contents, fileType) => { + const formatter: Formatter = async (contents) => { // Simulate async operation await new Promise((resolve) => setTimeout(resolve, 1)); return `ASYNC_FORMATTED: ${contents}`; From dab6f6b918e68bc2f1b35a77a49fcb5d43638216 Mon Sep 17 00:00:00 2001 From: Daniel Sitek Date: Sun, 9 Nov 2025 18:52:08 +0100 Subject: [PATCH 4/5] Fix code quality issues --- src/index.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index e3919d2..51225ef 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -267,7 +267,7 @@ describe('gulpTateru', () => { it('should apply both formatter and minify functions together', async () => { const formatter: Formatter = async (contents, fileType) => - await `FORMATTED (${fileType}): ${contents}`; + `FORMATTED (${fileType}): ${contents}`; const minify: Minify = async (contents) => contents.replace(/\s+/g, ' '); const { generatedFile } = await new Promise<{ @@ -300,7 +300,7 @@ describe('gulpTateru', () => { it('should handle different file types correctly', async () => { const formatterCalls: { contents: string; fileType: string }[] = []; const formatter: Formatter = async (contents, fileType) => { - await formatterCalls.push({ contents, fileType: fileType ?? 'unknown' }); + formatterCalls.push({ contents, fileType: fileType ?? 'unknown' }); return contents; }; From a8faabf722f311a22ec884596961595a48a5c454 Mon Sep 17 00:00:00 2001 From: Daniel Sitek Date: Sun, 9 Nov 2025 18:55:24 +0100 Subject: [PATCH 5/5] Fix code quality issues --- src/index.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index 51225ef..cac7126 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -301,7 +301,7 @@ describe('gulpTateru', () => { const formatterCalls: { contents: string; fileType: string }[] = []; const formatter: Formatter = async (contents, fileType) => { formatterCalls.push({ contents, fileType: fileType ?? 'unknown' }); - return contents; + return Promise.resolve(contents); }; await new Promise((resolve) => {