/* global expect jest */ const { mergeChallenges, translateComments, translateCommentsInChallenge } = require('.'); const { ENGLISH_CERTIFICATE, ENGLISH_CHALLENGE, ENGLISH_CHALLENGE_NO_FILES, ENGLISH_CHALLENGE_TWO_SOLUTIONS, ENGLISH_VIDEO_CHALLENGE, TRANSLATED_CERTIFICATE, TRANSLATED_CHALLENGE, TRANSLATED_CHALLENGE_NO_TITLE, TRANSLATED_VIDEO_CHALLENGE // WRONG_NUM_TESTS_CHALLENGE } = require('./__fixtures__/challenge-objects'); const { SIMPLE_TRANSLATION } = require('./__mocks__/mock-comments'); const COMBINED_CHALLENGE = mergeChallenges( ENGLISH_CHALLENGE, TRANSLATED_CHALLENGE ); const COMBINED_CHALLENGE_NO_TITLE = mergeChallenges( ENGLISH_CHALLENGE, TRANSLATED_CHALLENGE_NO_TITLE ); const COMBINED_CHALLENGE_TWO_SOLUTIONS = mergeChallenges( ENGLISH_CHALLENGE_TWO_SOLUTIONS, TRANSLATED_CHALLENGE ); const COMBINED_CERTIFICATE = mergeChallenges( ENGLISH_CERTIFICATE, TRANSLATED_CERTIFICATE ); const COMBINED_VIDEO_CHALLENGE = mergeChallenges( ENGLISH_VIDEO_CHALLENGE, TRANSLATED_VIDEO_CHALLENGE ); let logSpy; describe('translation parser', () => { beforeEach(() => { logSpy = jest.spyOn(console, 'warn').mockImplementation(); }); afterEach(() => { logSpy.mockRestore(); }); describe('mergeChallenges', () => { it('takes the description from the second challenge', () => { expect(COMBINED_CHALLENGE.description).toBe( TRANSLATED_CHALLENGE.description ); }); it('takes the head and tail from the first challenge', () => { expect(COMBINED_CHALLENGE.files[0].head).toBe( ENGLISH_CHALLENGE.files[0].head ); expect(COMBINED_CHALLENGE.files[0].tail).toBe( ENGLISH_CHALLENGE.files[0].tail ); }); it('takes the instructions from the second challenge', () => { expect(COMBINED_CHALLENGE.instructions).toBe( TRANSLATED_CHALLENGE.instructions ); }); it('takes the seed from the first challenge', () => { expect(COMBINED_CHALLENGE.files[0].contents).toBe( ENGLISH_CHALLENGE.files[0].contents ); }); it('takes the solution from the first challenge', () => { expect(COMBINED_CHALLENGE.solutions[0]).toBe( ENGLISH_CHALLENGE.solutions[0] ); }); it('takes multiple solutions', () => { expect(COMBINED_CHALLENGE_TWO_SOLUTIONS.solutions).toEqual( ENGLISH_CHALLENGE_TWO_SOLUTIONS.solutions ); }); it('takes the testStrings from the first challenge', () => { const actualStrings = COMBINED_CHALLENGE.tests.map( ({ testString }) => testString ); const expectedStrings = ENGLISH_CHALLENGE.tests.map( ({ testString }) => testString ); for (let i = 0; i < actualStrings.length; i++) { expect(actualStrings[i]).toBe(expectedStrings[i]); } }); it('takes the test text from the second challenge', () => { const actualStrings = COMBINED_CHALLENGE.tests.map(({ text }) => text); const expectedStrings = TRANSLATED_CHALLENGE.tests.map( ({ text }) => text ); for (let i = 0; i < actualStrings.length; i++) { expect(actualStrings[i]).toBe(expectedStrings[i]); } }); it('takes the title from the second challenge', () => { expect(COMBINED_CHALLENGE.title).toBe(TRANSLATED_CHALLENGE.title); }); // TODO: throw in production? it("takes the first challenge's title if the second is missing", () => { expect(COMBINED_CHALLENGE_NO_TITLE.title).toBe(ENGLISH_CHALLENGE.title); }); // 'originalTitle' is just used to create the dashedName (which must be // the same in both challenges, but only gets added after parsing) it('creates originalTitle from the first challenge', () => { expect(COMBINED_CHALLENGE.originalTitle).toBe(ENGLISH_CHALLENGE.title); }); // TODO: reinstate this after alpha testing. // it('throws an error if the numbers of tests do not match', () => { // expect(() => // mergeChallenges(ENGLISH_CHALLENGE, WRONG_NUM_TESTS_CHALLENGE) // ).toThrow(); // }); it('takes the forum id from the second challenge', () => { expect(COMBINED_CHALLENGE.forumTopicId).toBe( TRANSLATED_CHALLENGE.forumTopicId ); }); it('takes the ids from the first certificate', () => { const actualIds = COMBINED_CERTIFICATE.tests.map(({ id }) => id); const expectedIds = ENGLISH_CERTIFICATE.tests.map(({ id }) => id); for (let i = 0; i < actualIds.length; i++) { expect(actualIds[i]).toBe(expectedIds[i]); } }); it('takes the titles from the second certificate', () => { const actualTitles = COMBINED_CERTIFICATE.tests.map(({ title }) => title); const expectedTitles = TRANSLATED_CERTIFICATE.tests.map( ({ title }) => title ); for (let i = 0; i < actualTitles.length; i++) { expect(actualTitles[i]).toBe(expectedTitles[i]); } }); it('certificates do not have a forumTopicId property', () => { expect(Object.keys(COMBINED_CERTIFICATE).includes('forumTopicId')).toBe( false ); }); it('takes the question from the second challenge', () => { expect(COMBINED_VIDEO_CHALLENGE.question).toBe( TRANSLATED_VIDEO_CHALLENGE.question ); }); }); describe('translateCommentsInChallenge', () => { it('returns a clone of the challenge if there are no comments', () => { expect( translateCommentsInChallenge( ENGLISH_CHALLENGE_NO_FILES, 'chinese', SIMPLE_TRANSLATION ) ).toEqual(ENGLISH_CHALLENGE_NO_FILES); }); }); describe('translateComments', () => { it('replaces single line English comments with their translations', () => { const seed = `// Add your code below this line Add your code above this line `; const transSeed = `// (Chinese) Add your code below this line (Chinese) Add your code above this line `; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( transSeed ); }); it('does not translate urls', () => { const seed = `http:// Add your code below this line Add your code above this line `; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( seed ); const seedS = `https:// Add your code below this line Add your code above this line `; expect( translateComments(seedS, 'chinese', SIMPLE_TRANSLATION, 'js') ).toBe(seedS); }); it('replaces inline English comments with their translations', () => { const seed = `inline comment // Add your code below this line Add your code above this line `; const transSeed = `inline comment // (Chinese) Add your code below this line (Chinese) Add your code above this line `; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( transSeed ); }); it('replaces multiple English comments with their translations', () => { const seed = `inline comment // Add your code below this line // Add your code below this line `; const transSeed = `inline comment // (Chinese) Add your code below this line (Chinese) // (Chinese) Add your code below this line (Chinese) `; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( transSeed ); }); it('replaces multiline English comments with their translations', () => { const seed = `multiline comment /* Add your code below this line */ /* Add your code above this line */ change code below this line `; const transSeed = `multiline comment /* (Chinese) Add your code below this line (Chinese) */ /* (Chinese) Add your code above this line (Chinese) */ change code below this line `; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( transSeed ); }); it('replaces repeated multiline comments with their translations', () => { const seed = `multiline comment /* Add your code below this line */ /* Add your code below this line */ change code below this line `; const transSeed = `multiline comment /* (Chinese) Add your code below this line (Chinese) */ /* (Chinese) Add your code below this line (Chinese) */ change code below this line `; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( transSeed ); }); it('ignores empty comments', () => { expect.assertions(1); const seed = '//'; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( seed ); }); it('only replaces text inside comments, not between them', () => { const seed = `multiline comment /* Add your code below this line */ /* Add your code above this line */ Add your code below this line /* */ `; const transSeed = `multiline comment /* (Chinese) Add your code below this line (Chinese) */ /* (Chinese) Add your code above this line (Chinese) */ Add your code below this line /* */ `; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( transSeed ); const seedTwo = `multiline /* */ Add your code below this line /* */ `; expect( translateComments(seedTwo, 'chinese', SIMPLE_TRANSLATION, 'js') ).toBe(seedTwo); }); it('replaces English html comments with their translations', () => { const seed = `
change code below this line `; const transSeed = `
change code below this line `; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toBe(transSeed); }); it('replaces css comments with their translations', () => { const seed = ``; const transSeed = ``; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toBe(transSeed); }); it('replaces multiple css comments with their translations', () => { const seed = ``; const transSeed = ``; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toBe(transSeed); }); it('ignores css comments outside style tags', () => { const seed = `/* Add your code below this line */`; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toBe(seed); }); it('ignores css comments between style tags', () => { const seed = ` /* Add your code below this line */ `; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toBe(seed); }); it('only replaces inside English html comments', () => { const seed = `
Add your code below this line `; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toBe(seed); }); it('replaces English JSX comments with their translations', () => { const seed = `{ /* Add your code below this line */ } { /* Add your code above this line */ } change code below this line `; const transSeed = `{ /* (Chinese) Add your code below this line (Chinese) */ } { /* (Chinese) Add your code above this line (Chinese) */ } change code below this line `; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'jsx') ).toBe(transSeed); }); it('replaces English script comments with their translations', () => { const seed = ``; const transSeed = ``; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toBe(transSeed); }); it('replaces multiple script comments with their translations', () => { const seed = ``; const transSeed = ``; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toBe(transSeed); }); it('ignores html comments inside JavaScript', () => { const seed = `
change code below this line `; expect(translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'js')).toBe( seed ); }); it('ignores html comments inside jsx', () => { const seed = `
change code below this line `; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'jsx') ).toBe(seed); }); it('throws if there is not an exact match (js)', () => { expect.assertions(2); const seedMulti = `/* Add your code below this line Add your code above this line */ change code below this line `; const seedInline = `// Add your code below this line, please`; expect(() => translateComments(seedMulti, 'chinese', SIMPLE_TRANSLATION, 'js') ).toThrow(); expect(() => translateComments(seedInline, 'chinese', SIMPLE_TRANSLATION, 'js') ).toThrow(); }); it('only replaces exact matches (jsx)', () => { expect.assertions(1); const seedMulti = `{ /* Add your code below this line Add your code above this line */ } change code below this line `; expect(() => translateComments(seedMulti, 'chinese', SIMPLE_TRANSLATION, 'jsx') ).toThrow(); }); it('only replaces exact matches (html)', () => { expect.assertions(1); const seed = `
change code below this line `; expect(() => translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'html') ).toThrow(); }); it('only translates jsx comments once', () => { const seed = `{ /* Add your code below this line */ }`; const transSeed = `{ /* (Chinese) Add your code below this line (Chinese) */ }`; expect( translateComments(seed, 'chinese', SIMPLE_TRANSLATION, 'jsx') ).toBe(transSeed); }); it('throws if the comment is not in the dictionary', () => { expect.assertions(6); const seedJSX = `{ /* this is not a comment */ }`; const seedInline = `// this is not a comment `; const seedMulti = `/* this is not a comment */`; const seedCSS = ``; const seedHTML = `
`; const seedScript = ``; expect(() => translateComments(seedJSX, 'chinese', SIMPLE_TRANSLATION, 'jsx') ).toThrow(); expect(() => translateComments(seedInline, 'chinese', SIMPLE_TRANSLATION, 'js') ).toThrow(); expect(() => translateComments(seedMulti, 'chinese', SIMPLE_TRANSLATION, 'js') ).toThrow(); expect(() => translateComments(seedCSS, 'chinese', SIMPLE_TRANSLATION, 'html') ).toThrow(); expect(() => translateComments(seedHTML, 'chinese', SIMPLE_TRANSLATION, 'html') ).toThrow(); expect(() => translateComments(seedScript, 'chinese', SIMPLE_TRANSLATION, 'html') ).toThrow(); }); }); });