Files
VRCX/src/shared/utils/__tests__/gallery.test.js

315 lines
11 KiB
JavaScript

import {
getPrintFileName,
getPrintLocalDate,
getEmojiFileName
} from '../gallery';
describe('Gallery Utils', () => {
describe('getPrintFileName', () => {
test('generates filename with createdAt', () => {
const print = {
authorName: 'TestUser',
createdAt: '2023-01-15T10:30:45.123Z',
id: 'print_12345'
};
const result = getPrintFileName(print);
expect(result).toContain('TestUser');
expect(result).toContain('print_12345');
expect(result).toContain('.png');
// Check date formatting - should replace : with - and T with _
expect(result).toMatch(
/\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\.\d{3}/
);
});
test('generates filename with timestamp fallback', () => {
const print = {
authorName: 'TestUser2',
timestamp: 1673776245123, // 2023-01-15T10:30:45.123Z
id: 'print_67890'
};
const result = getPrintFileName(print);
expect(result).toContain('TestUser2');
expect(result).toContain('print_67890');
expect(result).toContain('.png');
});
test('generates filename with current date fallback', () => {
const print = {
authorName: 'TestUser3',
id: 'print_fallback'
};
const result = getPrintFileName(print);
expect(result).toContain('TestUser3');
expect(result).toContain('print_fallback');
expect(result).toContain('.png');
// Should still have valid date format
expect(result).toMatch(
/\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\.\d{3}/
);
});
test('handles missing authorName', () => {
const print = {
createdAt: '2023-01-15T10:30:45.123Z',
id: 'print_no_author'
};
const result = getPrintFileName(print);
expect(result).toContain('undefined_'); // authorName will be undefined
expect(result).toContain('print_no_author');
});
test('handles special characters in authorName', () => {
const print = {
authorName: 'Test User / With : Chars',
createdAt: '2023-01-15T10:30:45.123Z',
id: 'print_special'
};
const result = getPrintFileName(print);
expect(result).toContain('Test User / With : Chars'); // Should preserve original chars
expect(result).toContain('print_special');
});
test('handles missing data gracefully', () => {
const print = { id: 'test' };
const result = getPrintFileName(print);
expect(typeof result).toBe('string');
expect(result).toContain('test');
expect(result).toContain('.png');
});
});
describe('getPrintLocalDate', () => {
test('converts createdAt to local date', () => {
const print = { createdAt: '2023-01-15T10:30:45.123Z' };
const result = getPrintLocalDate(print);
expect(result).toBeInstanceOf(Date);
// Should have timezone offset applied
const originalDate = new Date('2023-01-15T10:30:45.123Z');
const expectedLocalTime =
originalDate.getTime() -
originalDate.getTimezoneOffset() * 60000;
expect(result.getTime()).toBe(expectedLocalTime);
});
test('uses timestamp without timezone conversion', () => {
const timestamp = 1673776245123; // 2023-01-15T10:30:45.123Z
const print = { timestamp };
const result = getPrintLocalDate(print);
expect(result).toBeInstanceOf(Date);
expect(result.getTime()).toBe(timestamp);
});
test('prefers createdAt over timestamp', () => {
const print = {
createdAt: '2023-01-15T10:30:45.123Z',
timestamp: 1673000000000 // Different timestamp
};
const result = getPrintLocalDate(print);
// Should use createdAt, not timestamp
const originalDate = new Date('2023-01-15T10:30:45.123Z');
const expectedLocalTime =
originalDate.getTime() -
originalDate.getTimezoneOffset() * 60000;
expect(result.getTime()).toBe(expectedLocalTime);
});
test('defaults to current date with timezone adjustment', () => {
const print = {};
const result = getPrintLocalDate(print);
expect(result).toBeInstanceOf(Date);
// Should be approximately current time with timezone offset
const currentDate = new Date();
const expectedLocalTime =
currentDate.getTime() - currentDate.getTimezoneOffset() * 60000;
// Allow some tolerance for execution time
expect(Math.abs(result.getTime() - expectedLocalTime)).toBeLessThan(
1000
);
});
test('handles invalid createdAt gracefully', () => {
const print = { createdAt: 'invalid-date' };
const result = getPrintLocalDate(print);
expect(result).toBeInstanceOf(Date);
// Should fall back to current date when createdAt is invalid
});
test('handles null/undefined inputs', () => {
expect(getPrintLocalDate({})).toBeInstanceOf(Date);
expect(getPrintLocalDate({ createdAt: null })).toBeInstanceOf(Date);
expect(getPrintLocalDate({ timestamp: null })).toBeInstanceOf(Date);
});
});
describe('getEmojiFileName', () => {
test('creates animated filename with all properties', () => {
const emoji = {
name: 'happy',
animationStyle: 'bounce',
frames: 10,
framesOverTime: 30,
loopStyle: 'loop'
};
const result = getEmojiFileName(emoji);
expect(result).toBe(
'happy_bounceanimationStyle_10frames_30fps_looploopStyle.png'
);
});
test('creates animated filename with default loopStyle', () => {
const emoji = {
name: 'wave',
animationStyle: 'wiggle',
frames: 5,
framesOverTime: 15
};
const result = getEmojiFileName(emoji);
expect(result).toBe(
'wave_wiggleanimationStyle_5frames_15fps_linearloopStyle.png'
);
});
test('creates static filename without frames', () => {
const emoji = {
name: 'smile',
animationStyle: 'static'
};
const result = getEmojiFileName(emoji);
expect(result).toBe('smile_staticanimationStyle.png');
});
test('treats zero frames as static', () => {
const emoji = {
name: 'neutral',
animationStyle: 'none',
frames: 0,
framesOverTime: 0
};
const result = getEmojiFileName(emoji);
expect(result).toBe('neutral_noneanimationStyle.png');
});
test('handles missing name gracefully', () => {
const emoji = {
animationStyle: 'bounce',
frames: 5,
framesOverTime: 10
};
const result = getEmojiFileName(emoji);
expect(result).toContain('undefined_bounceanimationStyle');
});
test('handles missing animationStyle', () => {
const emoji = {
name: 'test',
frames: 3,
framesOverTime: 20
};
const result = getEmojiFileName(emoji);
expect(result).toContain('test_undefinedanimationStyle');
});
test('handles special characters in name', () => {
const emoji = {
name: 'emoji-with_special.chars',
animationStyle: 'bounce',
frames: 8,
framesOverTime: 24,
loopStyle: 'pingpong'
};
const result = getEmojiFileName(emoji);
expect(result).toBe(
'emoji-with_special.chars_bounceanimationStyle_8frames_24fps_pingpongloopStyle.png'
);
});
test('handles edge case values', () => {
const emoji = {
name: '',
animationStyle: '',
frames: -1,
framesOverTime: 0,
loopStyle: ''
};
const result = getEmojiFileName(emoji);
// Should still generate a valid filename structure
expect(result).toContain('animationStyle');
expect(result).toContain('.png');
});
});
describe('integration and edge cases', () => {
test('getPrintFileName produces valid file names', () => {
const testCases = [
{
print: {
authorName: 'ValidUser',
createdAt: '2023-12-31T23:59:59.999Z',
id: 'print_test123'
},
expectValid: true
},
{
print: {
authorName: '',
createdAt: '2023-01-01T00:00:00.000Z',
id: ''
},
expectValid: true
},
{
print: {},
expectValid: true
}
];
testCases.forEach(({ print, expectValid }) => {
const result = getPrintFileName(print);
if (expectValid) {
expect(result).toMatch(/.*\.png$/);
expect(result.length).toBeGreaterThan(0);
}
});
});
test('date functions handle timezone consistency', () => {
const testDate = '2023-06-15T12:00:00.000Z';
const print = { createdAt: testDate };
const localDate = getPrintLocalDate(print);
const fileName = getPrintFileName({
...print,
authorName: 'test',
id: 'test'
});
// Both functions should produce consistent results
expect(localDate).toBeInstanceOf(Date);
expect(fileName).toMatch(
/test_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\.\d{3}_test\.png/
);
});
test('emoji filename handles boundary conditions', () => {
const extremeCases = [
{ name: 'a'.repeat(100), animationStyle: 'test' },
{ name: 'テスト', animationStyle: 'unicode' },
{
name: 'test',
animationStyle: 'test',
frames: 999,
framesOverTime: 999
}
];
extremeCases.forEach((emoji) => {
const result = getEmojiFileName(emoji);
expect(typeof result).toBe('string');
expect(result.endsWith('.png')).toBe(true);
});
});
});
});