diff --git a/.eslintrc.json b/.eslintrc.json index 44b94ec2..afa848f6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,7 +5,8 @@ "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended", "plugin:typescript-sort-keys/recommended", - "plugin:jest/recommended" + "plugin:jest/recommended", + "turbo" ], "plugins": [ "sort-destructure-keys", diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 64207018..a836f893 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,6 @@ jobs: MYSQL_DATABASE: test MYSQL_PORT: 3306 DATABASE_URL: mysql://root:root@127.0.0.1:3306/test - TEST_DATABASE_URL: mysql://root:root@127.0.0.1:3306/test CONVERTKIT_API_KEY: api_key CONVERTKIT_FORM_ID: form_id outputs: diff --git a/package.json b/package.json index c0dc8f0f..5f53da6d 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "dotenv-cli": "7.4.2", "eslint": "8.56.0", "eslint-config-prettier": "9.1.0", + "eslint-config-turbo": "2.0.3", "eslint-plugin-import": "2.29.1", "eslint-plugin-jest": "27.9.0", "eslint-plugin-prettier": "5.1.3", diff --git a/packages/domain/package.json b/packages/domain/package.json index a3d65229..f77cef5c 100644 --- a/packages/domain/package.json +++ b/packages/domain/package.json @@ -25,7 +25,7 @@ "db:seed": "yarn env -- prisma db seed", "db:test": "zx tests/database.mjs", "db:test:stop": "docker container kill snipcode-test-db && docker container prune -f", - "test": "NODE_ENV=test yarn db:test && dotenv -e .env.test -- jest" + "test": "NODE_ENV=test yarn db:test && dotenv -e .env.test -- jest --runInBand" }, "dependencies": { "@bugsnag/cuid": "3.1.1", diff --git a/packages/domain/src/services/folders/inputs/create-folder-input.test.ts b/packages/domain/src/services/folders/inputs/create-folder-input.test.ts index 357fd9cd..63785735 100644 --- a/packages/domain/src/services/folders/inputs/create-folder-input.test.ts +++ b/packages/domain/src/services/folders/inputs/create-folder-input.test.ts @@ -3,17 +3,14 @@ import { Folder } from '../folder.entity'; describe('Test Create Folder Input', () => { it('should create a valid folder object', () => { - // GIVEN const input = new CreateFolderInput({ name: 'blogs', parentId: 'cl23rzwe5000002czaedc8sll', userId: 'dm34saxf6111113dabfed9tmm', }); - // WHEN const folder = input.toFolder(); - // THEN expect(folder).toMatchObject({ createdAt: expect.any(Date), id: expect.any(String), @@ -27,7 +24,6 @@ describe('Test Create Folder Input', () => { }); it('should create the valid folder name', () => { - // GIVEN const input = new CreateFolderInput({ name: 'blogs', parentId: 'cl23rzwe5000002czaedc8sll', @@ -35,13 +31,10 @@ describe('Test Create Folder Input', () => { }); const expectedFolderName = 'blogs'; - // WHEN - // THEN expect(input.name).toEqual(expectedFolderName); }); it('should create the valid folder parent id', () => { - // GIVEN const input = new CreateFolderInput({ name: 'blogs', parentId: 'cl23rzwe5000002czaedc8sll', @@ -49,13 +42,10 @@ describe('Test Create Folder Input', () => { }); const expectedParentId = 'cl23rzwe5000002czaedc8sll'; - // WHEN - // THEN expect(input.parentFolderId).toEqual(expectedParentId); }); it('should create the valid folder user id', () => { - // GIVEN const input = new CreateFolderInput({ name: 'blogs', parentId: 'cl23rzwe5000002czaedc8sll', @@ -63,8 +53,6 @@ describe('Test Create Folder Input', () => { }); const expectedUserId = 'dm34saxf6111113dabfed9tmm'; - // WHEN - // THEN expect(input.user).toEqual(expectedUserId); }); }); diff --git a/packages/domain/src/services/folders/utils/folders.test.ts b/packages/domain/src/services/folders/utils/folders.test.ts index d7659522..15c6ef72 100644 --- a/packages/domain/src/services/folders/utils/folders.test.ts +++ b/packages/domain/src/services/folders/utils/folders.test.ts @@ -4,7 +4,6 @@ import { Folder } from '../folder.entity'; describe('Test folders utilities', () => { it('should assert the folders contain the root folder', () => { - // GIVEN const userId = TestHelper.generateTestId(); const rootFolder = TestHelper.createTestFolderInput({ userId }).toFolder(); @@ -13,15 +12,12 @@ describe('Test folders utilities', () => { const foldersToDelete: Folder[] = [TestHelper.createTestFolderInput({ userId }).toFolder(), rootFolder]; - // WHEN const isValid = isFoldersContainRoot(foldersToDelete); - // THEN expect(isValid).toEqual(true); }); it("should assert the folders doesn't contain the root folder", () => { - // GIVEN const userId = TestHelper.generateTestId(); const foldersToDelete: Folder[] = [ @@ -29,10 +25,8 @@ describe('Test folders utilities', () => { TestHelper.createTestFolderInput({ userId }).toFolder(), ]; - // WHEN const isValid = isFoldersContainRoot(foldersToDelete); - // THEN expect(isValid).toEqual(false); }); }); diff --git a/packages/domain/src/services/newsletters/newsletter.service.test.ts b/packages/domain/src/services/newsletters/newsletter.service.test.ts index 20ec9eaa..8b065adb 100644 --- a/packages/domain/src/services/newsletters/newsletter.service.test.ts +++ b/packages/domain/src/services/newsletters/newsletter.service.test.ts @@ -26,7 +26,6 @@ describe('Newsletter service', () => { }); test('Add the email address to the newsletter subscribers', async () => { - // GIVEN const emailToSubscribe = 'user@email.com'; const tags = ['snipcode']; const formId = 'formId'; @@ -43,17 +42,14 @@ describe('Newsletter service', () => { }, }); - // WHEN await newsletterService.subscribe(emailToSubscribe, tags); - // THEN expect(scope.isDone()).toBe(true); nock.cleanAll(); }); test('Handle HTTP error when the request to add the email address to the newsletter subscribers fails', async () => { - // GIVEN const emailToSubscribe = 'user@email.com'; const tags = ['snipcode']; const formId = 'formId'; @@ -68,8 +64,6 @@ describe('Newsletter service', () => { message: 'Wrong api key provided!', }); - // WHEN - // THEN const caughtErrorsFormatted = { data: { message: 'Wrong api key provided!', diff --git a/packages/domain/src/services/sessions/session.service.test.ts b/packages/domain/src/services/sessions/session.service.test.ts index b4cdd4d9..54b7f7cd 100644 --- a/packages/domain/src/services/sessions/session.service.test.ts +++ b/packages/domain/src/services/sessions/session.service.test.ts @@ -26,36 +26,29 @@ describe('Test Session Service', function () { testHelper = new TestHelper(prismaService); }); - it('should create a session', async () => { - // GIVEN + test('Create a session', async () => { const userId = TestHelper.generateTestId(); const input = TestHelper.createTestSessionInput(userId); - // WHEN const sessionCreated = await sessionService.create(input); - // THEN expect(sessionCreated).toMatchObject(input.toSession()); await testHelper.deleteTestUserSessions(sessionCreated.userId); }); - it('should find a session by token', async () => { - // GIVEN + test('Retrieve a session by the token attached to it', async () => { const userId = TestHelper.generateTestId(); const session = await testHelper.createTestSession({ userId }); - // WHEN const sessionFound = await sessionService.findByToken(session.token); - // THEN expect(session).toEqual(sessionFound); await testHelper.deleteTestUserSessions(session.userId); }); - it('should delete all session of a user', async () => { - // GIVEN + test('Delete all sessions of a user', async () => { const userId = TestHelper.generateTestId(); const sessionsCreated = await Promise.all([ @@ -64,10 +57,8 @@ describe('Test Session Service', function () { testHelper.createTestSession({ userId }), ]); - // WHEN await sessionService.deleteUserSessions(userId); - // THEN const userSessions = await Promise.all(sessionsCreated.map(({ token }) => sessionService.findByToken(token))); expect(userSessions.every((session) => !session)).toBe(true); diff --git a/packages/domain/src/services/snippets/inputs/create-snippet-input.test.ts b/packages/domain/src/services/snippets/inputs/create-snippet-input.test.ts index d9bdd802..d07b514d 100644 --- a/packages/domain/src/services/snippets/inputs/create-snippet-input.test.ts +++ b/packages/domain/src/services/snippets/inputs/create-snippet-input.test.ts @@ -7,7 +7,6 @@ describe('Test Create Snippet Input', () => { const folderId = TestHelper.generateTestId(); const userId = TestHelper.generateTestId(); - // GIVEN const input = new CreateSnippetInput({ content: 'import React from "react";\n\nexport const App = () => {\n\n\treturn(\n\t\t
Hello
\n\t);\n};', contentHighlighted: @@ -22,10 +21,8 @@ describe('Test Create Snippet Input', () => { visibility: 'public', }); - // WHEN const folder = input.toSnippet(); - // THEN expect(folder).toMatchObject({ content: 'import React from "react";\n\nexport const App = () => {\n\n\treturn(\n\t\t
Hello
\n\t);\n};', contentHtml: diff --git a/packages/domain/src/services/snippets/inputs/delete-snippet-input.test.ts b/packages/domain/src/services/snippets/inputs/delete-snippet-input.test.ts index 86f3993f..fbdbde96 100644 --- a/packages/domain/src/services/snippets/inputs/delete-snippet-input.test.ts +++ b/packages/domain/src/services/snippets/inputs/delete-snippet-input.test.ts @@ -6,14 +6,11 @@ describe('Test Delete Snippet Input', () => { const snippetId = TestHelper.generateTestId(); const userId = TestHelper.generateTestId(); - // GIVEN const input = new DeleteSnippetInput({ creatorId: userId, snippetId, }); - // WHEN - // THEN expect(input.snippetId).toEqual(snippetId); expect(input.creatorId).toEqual(userId); }); diff --git a/packages/domain/src/services/snippets/snippet.service.test.ts b/packages/domain/src/services/snippets/snippet.service.test.ts index 64717db5..d48f48df 100644 --- a/packages/domain/src/services/snippets/snippet.service.test.ts +++ b/packages/domain/src/services/snippets/snippet.service.test.ts @@ -34,15 +34,12 @@ describe('Test Snippet service', () => { await roleService.loadRoles(); }); - it('should create a snippet in the specified folder', async () => { - // GIVEN + test('Create a snippet in a folder', async () => { const [user, rootFolder] = await testHelper.createUserWithRootFolder(); const createSnippetInput = TestHelper.createTestSnippetInput({ folderId: rootFolder.id, userId: user.id }); - // WHEN const expectedSnippet = await snippetService.create(createSnippetInput); - // THEN expect(expectedSnippet).toMatchObject({ content: createSnippetInput.toSnippet().content, contentHtml: createSnippetInput.toSnippet().contentHtml, @@ -65,13 +62,10 @@ describe('Test Snippet service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should not create a snippet because the specified folder does not exist', async () => { - // GIVEN + test('Can not create a snippet because the specified folder does not exist', async () => { const [user, rootFolder] = await testHelper.createUserWithRootFolder(); const createSnippetInput = TestHelper.createTestSnippetInput({ folderId: generateRandomId(), userId: user.id }); - // WHEN - // THEN await expect(async () => { await snippetService.create(createSnippetInput); }).rejects.toThrow(new AppError(errors.FOLDER_NOT_FOUND(createSnippetInput.folderId), 'FOLDER_NOT_FOUND')); @@ -80,8 +74,7 @@ describe('Test Snippet service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should not create a snippet because it already exists in the specified folder', async () => { - // GIVEN + test('Can not create a snippet because it already exists in the specified folder', async () => { const [user, rootFolder] = await testHelper.createUserWithRootFolder(); const snippet = await testHelper.createTestSnippet({ folderId: rootFolder.id, name: 'app.tsx', userId: user.id }); @@ -91,8 +84,6 @@ describe('Test Snippet service', () => { userId: user.id, }); - // WHEN - // THEN await expect(() => snippetService.create(sameCreateSnippetInput)).rejects.toThrow( new AppError(errors.SNIPPET_ALREADY_EXIST(sameCreateSnippetInput.name), 'SNIPPET_ALREADY_EXIST'), ); @@ -102,8 +93,7 @@ describe('Test Snippet service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should retrieve all public snippets', async () => { - // GIVEN + test('Retrieve all the public snippets', async () => { const [user, rootFolder] = await testHelper.createUserWithRootFolder(); const existingSnippets = await Promise.all([ testHelper.createTestSnippet({ folderId: rootFolder.id, userId: user.id, visibility: 'public' }), @@ -114,21 +104,18 @@ describe('Test Snippet service', () => { testHelper.createTestSnippet({ folderId: rootFolder.id, userId: user.id, visibility: 'public' }), ]); - // WHEN const publicSnippets = await snippetService.findPublicSnippet({ itemPerPage: 10 }); - // THEN - await expect(publicSnippets.hasMore).toEqual(false); - await expect(publicSnippets.nextCursor).toEqual(null); - await expect(publicSnippets.items).toHaveLength(4); + expect(publicSnippets.hasMore).toEqual(false); + expect(publicSnippets.nextCursor).toEqual(null); + expect(publicSnippets.items).toHaveLength(4); await testHelper.deleteTestSnippetsById(existingSnippets.map((snippet) => snippet.id)); await testHelper.deleteTestFoldersById([rootFolder.id]); await testHelper.deleteTestUsersById([user.id]); }); - it('should retrieve a subset of public snippets', async () => { - // GIVEN + test('Retrieve three public snippets per page', async () => { const [user, rootFolder] = await testHelper.createUserWithRootFolder(); const existingSnippets = await Promise.all([ testHelper.createTestSnippet({ folderId: rootFolder.id, userId: user.id, visibility: 'public' }), @@ -139,21 +126,18 @@ describe('Test Snippet service', () => { testHelper.createTestSnippet({ folderId: rootFolder.id, userId: user.id, visibility: 'public' }), ]); - // WHEN const publicSnippets = await snippetService.findPublicSnippet({ itemPerPage: 3 }); - // THEN - await expect(publicSnippets.hasMore).toEqual(true); - await expect(publicSnippets.nextCursor).toEqual(expect.any(String)); - await expect(publicSnippets.items).toHaveLength(3); + expect(publicSnippets.hasMore).toEqual(true); + expect(publicSnippets.nextCursor).toEqual(expect.any(String)); + expect(publicSnippets.items).toHaveLength(3); await testHelper.deleteTestSnippetsById(existingSnippets.map((snippet) => snippet.id)); await testHelper.deleteTestFoldersById([rootFolder.id]); await testHelper.deleteTestUsersById([user.id]); }); - it('should find all snippets of a user', async () => { - // GIVEN + test('Retrieve all snippets belonging to a user', async () => { const [user1, rootFolder1] = await testHelper.createUserWithRootFolder(); const [user2, rootFolder2] = await testHelper.createUserWithRootFolder(); @@ -166,19 +150,16 @@ describe('Test Snippet service', () => { testHelper.createTestSnippet({ folderId: rootFolder2.id, userId: user2.id, visibility: 'private' }), ]); - // WHEN const userSnippets = await snippetService.findByUser(user2.id); - // THEN - await expect(userSnippets).toHaveLength(3); + expect(userSnippets).toHaveLength(3); await testHelper.deleteTestSnippetsById(existingSnippets.map((snippet) => snippet.id)); await testHelper.deleteTestFoldersById([rootFolder1.id, rootFolder2.id]); await testHelper.deleteTestUsersById([user1.id, user2.id]); }); - it('should retrieve a snippet by its ID', async () => { - // GIVEN + test('Retrieve a snippet by its ID', async () => { const [user1, rootFolder1] = await testHelper.createUserWithRootFolder(); const snippet = await testHelper.createTestSnippet({ @@ -187,10 +168,8 @@ describe('Test Snippet service', () => { visibility: 'public', }); - // WHEN const snippetFound = await snippetService.findById(snippet.id); - // THEN expect(snippetFound).toMatchObject({ folderId: rootFolder1.id, id: snippet.id, @@ -203,19 +182,15 @@ describe('Test Snippet service', () => { await testHelper.deleteTestUsersById([user1.id]); }); - it('should found no snippet given the ID provided', async () => { - // GIVEN + test("Can not find a snippet by the ID because it doesn't exists", async () => { const snippetId = generateRandomId(); - // WHEN - // THEN await expect(async () => { await snippetService.findById(snippetId); }).rejects.toThrow(new AppError(errors.SNIPPET_NOT_FOUND(snippetId), 'SNIPPET_NOT_FOUND')); }); - it('should delete an existing snippet belonging to a user', async () => { - // GIVEN + test('Delete a snippet belonging to a user', async () => { const [user, rootFolder] = await testHelper.createUserWithRootFolder(); const [snippet1, snippet2] = await Promise.all([ @@ -223,12 +198,10 @@ describe('Test Snippet service', () => { testHelper.createTestSnippet({ folderId: rootFolder.id, userId: user.id, visibility: 'private' }), ]); - // WHEN const deleteSnippetInput = TestHelper.deleteTestSnippetInput({ snippetId: snippet1.id, userId: snippet1.userId }); await snippetService.delete(deleteSnippetInput); - // THEN const folderSnippets = await snippetService.findByFolder(rootFolder.id); expect(folderSnippets).toHaveLength(1); @@ -238,8 +211,7 @@ describe('Test Snippet service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should not delete an existing snippet because it belongs to other user', async () => { - // GIVEN + test('Can not delete a snippet belonging to other user', async () => { const [user1, rootFolder1] = await testHelper.createUserWithRootFolder(); const [user2, rootFolder2] = await testHelper.createUserWithRootFolder(); @@ -249,10 +221,8 @@ describe('Test Snippet service', () => { testHelper.createTestSnippet({ folderId: rootFolder1.id, userId: user1.id, visibility: 'private' }), ]); - // WHEN const deleteSnippetInput = TestHelper.deleteTestSnippetInput({ snippetId: snippet1.id, userId: user2.id }); - // THEN await expect(async () => { await snippetService.delete(deleteSnippetInput); }).rejects.toThrow( @@ -270,8 +240,7 @@ describe('Test Snippet service', () => { await testHelper.deleteTestUsersById([user1.id, user2.id]); }); - it('should update an existing snippet in the specified folder', async () => { - // GIVEN + test('Update a snippet in a folder', async () => { const [user, rootFolder] = await testHelper.createUserWithRootFolder(); const snippet = await testHelper.createTestSnippet({ folderId: rootFolder.id, @@ -281,10 +250,8 @@ describe('Test Snippet service', () => { const updateSnippetInput = TestHelper.updateTestSnippetInput({ snippetId: snippet.id, userId: user.id }); - // WHEN const updatedSnippet = await snippetService.update(updateSnippetInput); - // THEN const snippetToUpdate = updateSnippetInput.toSnippet(snippet); expect(updatedSnippet).toMatchObject({ @@ -309,8 +276,7 @@ describe('Test Snippet service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should not update an existing snippet in the specified folder because another snippet with the updated name already exists in the folder', async () => { - // GIVEN + test('Can not update a snippet in a folder because another snippet with the updated name already exists inside', async () => { const [user, rootFolder] = await testHelper.createUserWithRootFolder(); const [snippet] = await Promise.all([ testHelper.createTestSnippet({ folderId: rootFolder.id, name: 'snippet-one.java', userId: user.id }), @@ -328,8 +294,6 @@ describe('Test Snippet service', () => { userId: user.id, }); - // WHEN - // THEN await expect(async () => { await snippetService.update(updateSnippetInput); }).rejects.toThrow(new AppError(errors.SNIPPET_ALREADY_EXIST(updateSnippetInput.name), 'SNIPPET_ALREADY_EXIST')); @@ -339,8 +303,7 @@ describe('Test Snippet service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should not update an existing snippet in the specified folder because because it belongs to other user', async () => { - // GIVEN + test('Can not update a snippet in a folder belonging to other user', async () => { const [user1, rootFolder1] = await testHelper.createUserWithRootFolder(); const [user2, rootFolder2] = await testHelper.createUserWithRootFolder(); const snippet = await testHelper.createTestSnippet({ @@ -351,8 +314,6 @@ describe('Test Snippet service', () => { const updateSnippetInput = TestHelper.updateTestSnippetInput({ snippetId: snippet.id, userId: user2.id }); - // WHEN - // THEN await expect(async () => { await snippetService.update(updateSnippetInput); }).rejects.toThrow( diff --git a/packages/domain/src/services/users/user.service.test.ts b/packages/domain/src/services/users/user.service.test.ts index ad0f0385..fb1462ad 100644 --- a/packages/domain/src/services/users/user.service.test.ts +++ b/packages/domain/src/services/users/user.service.test.ts @@ -33,9 +33,9 @@ describe('Test User service', () => { await roleService.loadRoles(); }); - it('should load users in the database', async () => { + test('Load users in the database', async () => { const [roleAdmin] = await roleService.findAll(); - const adminPassword = 'VerStrongPassword'; + const adminPassword = 'VeryStrongPassword'; await userService.loadAdminUser(roleAdmin, adminPassword); @@ -46,15 +46,12 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([adminUser?.id]); }); - it('should create a user', async () => { - // GIVEN + test('Create a user', async () => { const role = await testHelper.findTestRole('user'); const createUserInput = TestHelper.createTestUserInput({ roleId: role.id }); - // WHEN const createdUser = await userService.create(createUserInput); - // THEN expect(createdUser).toMatchObject({ createdAt: expect.any(Date), email: createUserInput.email, @@ -73,15 +70,12 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([createdUser.id]); }); - it('should create a user with no username', async () => { - // GIVEN + test('Create a user with no username', async () => { const role = await testHelper.findTestRole('user'); const createUserInput = TestHelper.createTestUserInput({ roleId: role.id, username: null }); - // WHEN const createdUser = await userService.create(createUserInput); - // THEN expect(createdUser).toMatchObject({ createdAt: expect.any(Date), email: createUserInput.email, @@ -100,33 +94,27 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([createdUser.id]); }); - it('should create a user with a username that already exists', async () => { - // GIVEN + test('Create a user with a username that already exists will generate a new one for him', async () => { const role = await testHelper.findTestRole('user'); const user = await testHelper.createTestUser({ username: 'roloto' }); - const createUserInput = await TestHelper.createTestUserInput({ roleId: role.id, username: 'roloto' }); + const createUserInput = TestHelper.createTestUserInput({ roleId: role.id, username: 'roloto' }); - // WHEN const createdUser = await userService.create(createUserInput); - // THEN expect(createdUser.username).not.toEqual('roloto'); await testHelper.deleteTestUsersById([user.id, createdUser.id]); }); - it('should create a user - validation check', async () => { - // GIVEN + test('Create a user - validation check', async () => { const role = await testHelper.findTestRole('user'); const createUserInput = TestHelper.createTestUserInput({ roleId: role.id }); createUserInput.isEnabled = true; - // WHEN const createdUser = await userService.create(createUserInput); - // THEN expect(createdUser).toMatchObject({ createdAt: expect.any(Date), email: createUserInput.email, @@ -145,14 +133,11 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([createdUser.id]); }); - it('should fail create a user because the email address already exists', async () => { - // GIVEN + test('Can not create a user because the email address already exists', async () => { const user = await testHelper.createTestUser({ email: 'user@email.com' }); const role = await testHelper.findTestRole('user'); const createUserInput = TestHelper.createTestUserInput({ email: 'user@email.com', roleId: role.id }); - // WHEN - // THEN await expect(async () => { await userService.create(createUserInput); }).rejects.toThrow(new AppError(errors.EMAIL_ALREADY_TAKEN, 'EMAIL_ALREADY_TAKEN')); @@ -160,17 +145,14 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should update user information', async () => { - // GIVEN + test('Update user information', async () => { const currentUser = await testHelper.createTestUser({}); const role = await testHelper.findTestRole('admin'); const updateUserInput = TestHelper.updateTestUserInput(role.id); - // WHEN const updatedUser = await userService.update(currentUser, updateUserInput); - // THEN expect(updatedUser).toMatchObject({ createdAt: expect.any(Date), email: currentUser.email, @@ -189,26 +171,20 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([currentUser.id]); }); - it("should fail to authenticate the user because the email doesn't exists", async () => { - // GIVEN + test("Fail to authenticate the user because the email doesn't exists", async () => { const userEmail = 'email@test.com'; const userPassword = 'strongPassword'; - // WHEN - // THEN await expect(() => userService.login(userEmail, userPassword)).rejects.toThrow( new AppError(errors.LOGIN_FAILED, 'LOGIN_FAILED'), ); }); - it('should fail to authenticate the user because the password is not correct', async () => { - // GIVEN + test('Fail to authenticate the user because the password is not correct', async () => { const userPassword = 'strongPassword'; const userBadPassword = 'badPassword'; const user = await testHelper.createTestUser({ oauthProvider: 'email', password: userPassword }); - // WHEN - // THEN await expect(() => userService.login(user.email, userBadPassword)).rejects.toThrow( new AppError(errors.LOGIN_FAILED, 'LOGIN_FAILED'), ); @@ -216,13 +192,10 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should fail to authenticate the user because the user is disabled', async () => { - // GIVEN + test('Fail to authenticate the user because the user is disabled', async () => { const userPassword = 'strongPassword'; const user = await testHelper.createTestUser({ oauthProvider: 'email', password: userPassword }); - // WHEN - // THEN await expect(() => userService.login(user.email, userPassword)).rejects.toThrow( new AppError(errors.ACCOUNT_DISABLED, 'ACCOUNT_DISABLED'), ); @@ -230,8 +203,7 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should successfully authenticate the user', async () => { - // GIVEN + test('Authenticate a user', async () => { const userPassword = 'strongPassword'; const user = await testHelper.createTestUser({ isEnabled: true, @@ -239,10 +211,8 @@ describe('Test User service', () => { password: userPassword, }); - // WHEN const authenticatedUser = await userService.login(user.email, userPassword); - // THEN expect(user).toMatchObject({ email: authenticatedUser.email, id: authenticatedUser.id, @@ -255,14 +225,11 @@ describe('Test User service', () => { await testHelper.deleteTestUsersById([user.id]); }); - it('should found no user given the ID provided', async () => { - // GIVEN + test("Can not find the user by its ID because it doesn't exist", async () => { const snippetId = generateRandomId(); - // WHEN const user = await userService.findById(snippetId); - // THEN expect(user).toBeNull(); }); }); diff --git a/packages/domain/src/utils/db-id.test.ts b/packages/domain/src/utils/db-id.test.ts index ae680c62..50e92c10 100644 --- a/packages/domain/src/utils/db-id.test.ts +++ b/packages/domain/src/utils/db-id.test.ts @@ -1,17 +1,17 @@ import { dbID } from './db-id'; describe('Test Database ID generator', () => { - test('generate a valid id', () => { + it('should generate a valid id', () => { const id = dbID.generate(); expect(dbID.isValid(id)).toEqual(true); }); - test.each([ + it.each([ ['myinvalidid', false], ['111111111111', false], ['cl1fny73o0000e7czbglkhv0p', true], - ])('detect validity of id %s', (id, expected) => { + ])('should validate the ID "%s" as "%s"', (id, expected) => { expect(dbID.isValid(id)).toEqual(expected); }); }); diff --git a/packages/domain/tsconfig.json b/packages/domain/tsconfig.json index d5304608..c4e94c18 100644 --- a/packages/domain/tsconfig.json +++ b/packages/domain/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "declaration": true, "composite": true, + "sourceMap": true, }, "exclude": ["node_modules", "dist"], "files": ["env.d.ts"], diff --git a/packages/embed/__tests__/oembed/generate-metadata.test.ts b/packages/embed/__tests__/oembed/generate-metadata.test.ts index b439bc44..888511f9 100644 --- a/packages/embed/__tests__/oembed/generate-metadata.test.ts +++ b/packages/embed/__tests__/oembed/generate-metadata.test.ts @@ -2,19 +2,16 @@ import { generateOembedMetadata } from '../../src/oembed'; describe('Test Generate Oembed metadata', () => { it('should generate Oembed metadata for a code snippet', () => { - // GIVEN const snippet = { id: 'snippet_id', name: 'snippet-name.java' }; const SNIPPET_RENDERER_URL = 'https://embed.snipcode.dev'; const WEB_APP_URL = 'https://snipcode.dev'; - // WHEN const result = generateOembedMetadata({ snippet, snippetRendererURL: SNIPPET_RENDERER_URL, webAppURL: WEB_APP_URL, }); - // THEN expect(result).toMatchInlineSnapshot(` { "height": 500, diff --git a/packages/embed/__tests__/renderer/content/html-generator.test.ts b/packages/embed/__tests__/renderer/content/html-generator.test.ts index 0ac2f1dd..f583314d 100644 --- a/packages/embed/__tests__/renderer/content/html-generator.test.ts +++ b/packages/embed/__tests__/renderer/content/html-generator.test.ts @@ -1,14 +1,11 @@ import { generateNoSnippetHtmlContent } from '../../../src/renderer/content/html-generator'; describe('Test HTML generator functions', () => { - it.only('should generates html content for a non existing code snippet', () => { - // GIVEN + it('should generates html content for a non existing code snippet', () => { const WEB_APP_URL = 'https://snipcode.dev'; - // WHEN const result = generateNoSnippetHtmlContent(WEB_APP_URL); - // THEN expect(result).toMatchInlineSnapshot(` "

Oops! Snippet not found!

diff --git a/packages/embed/__tests__/renderer/content/preview-template.test.ts b/packages/embed/__tests__/renderer/content/preview-template.test.ts index 3014debb..e12262ab 100644 --- a/packages/embed/__tests__/renderer/content/preview-template.test.ts +++ b/packages/embed/__tests__/renderer/content/preview-template.test.ts @@ -7,8 +7,11 @@ jest.mock('../../../src/renderer/content/utils', () => { }); describe('Test generateHTMLPreview()', () => { + afterAll(() => { + jest.clearAllMocks(); + }); + it('should generates the html preview for a code snippet', () => { - // GIVEN const args: Args = { code: 'export const hashPassword = (password: string): string => {\n' + @@ -23,16 +26,14 @@ describe('Test generateHTMLPreview()', () => { '\n' + ' return bcrypt.hashSync(password, SALT_ROUNDS);\n' + '};', - scriptUrl: 'https://cdn.com/sharigan/script.js', - styleUrl: 'https://cdn.com/sharigan/style.css', + scriptUrl: 'https://cdn.com/snipcode/script.js', + styleUrl: 'https://cdn.com/snipcode/style.css', title: 'helpers.ts', webAppUrl: 'https://snipcode.dev', }; - // WHEN const result = generateHTMLPreview(args); - // THEN expect(result).toMatchInlineSnapshot(` " @@ -42,7 +43,7 @@ describe('Test generateHTMLPreview()', () => { Snipcode - helpers.ts - +
@@ -71,7 +72,7 @@ describe('Test generateHTMLPreview()', () => { };
- + " diff --git a/packages/embed/__tests__/renderer/content/utils.test.ts b/packages/embed/__tests__/renderer/content/utils.test.ts index 55c7b0db..6265dd31 100644 --- a/packages/embed/__tests__/renderer/content/utils.test.ts +++ b/packages/embed/__tests__/renderer/content/utils.test.ts @@ -7,34 +7,25 @@ import { describe('Test utils functions', () => { describe('Test addWhitespaceForEmptyLine()', () => { it('should create not whitespace for a simple span tag', () => { - // GIVEN const line = ``; - // WHEN const result = addWhitespaceForEmptyLine(line); - // THEN expect(result).toEqual(``); }); it('should create whitespace for a code line', () => { - // GIVEN const line = ``; - // WHEN const result = addWhitespaceForEmptyLine(line); - // THEN expect(result).toEqual(`  `); }); it('should create whitespace for a code line with highlight', () => { - // GIVEN const line = ``; - // WHEN const result = addWhitespaceForEmptyLine(line); - // THEN expect(result).toEqual(`  `); }); @@ -42,35 +33,26 @@ describe('Test utils functions', () => { describe('Test generateLineHighlightOptions()', () => { it('should generate no line highlight options from a null string', () => { - // GIVEN const lineHighlight: string | null = null; - // WHEN const result = generateLineHighlightOptions(lineHighlight); - // THEN expect(result).toMatchObject([]); }); it('should generate no line highlight options from an empty string', () => { - // GIVEN const lineHighlight = `[]`; - // WHEN const result = generateLineHighlightOptions(lineHighlight); - // THEN expect(result).toMatchObject([]); }); it('should generate line highlight options from string', () => { - // GIVEN const lineHighlight = `[[3,"delete"],[6,"blur"],[7,"add"]]`; - // WHEN const result = generateLineHighlightOptions(lineHighlight); - // THEN const expectedResult = [ { classes: ['line-diff line-diff-delete'], line: 3 }, { classes: ['line-diff line-diff-blur'], line: 6 }, @@ -83,13 +65,10 @@ describe('Test utils functions', () => { describe('Test parseHTMLSnippetCode()', () => { it('should parse html snippet code', () => { - // GIVEN const htmlCode = `
line code 1\n\nline code 3
`; - // WHEN const result = parseHTMLSnippetCode(htmlCode); - // THEN expect(result).toEqual( `1line code 1\n2  \n3line code 3`, ); diff --git a/packages/embed/jest.config.ts b/packages/embed/jest.config.ts index afeaf065..c0f92394 100644 --- a/packages/embed/jest.config.ts +++ b/packages/embed/jest.config.ts @@ -7,6 +7,7 @@ const config: Config.InitialOptions = { testEnvironment: 'node', clearMocks: true, maxWorkers: 1, + prettierPath: require.resolve('prettier-2'), // Waiting for the release of v30 to use Prettier 3 snapshotFormat: { printBasicPrototype: false, }, diff --git a/packages/embed/package.json b/packages/embed/package.json index 4bd1c5ae..5994b785 100644 --- a/packages/embed/package.json +++ b/packages/embed/package.json @@ -25,6 +25,7 @@ "@types/express": "4.17.21", "express": "4.19.1", "nodemon": "2.0.22", + "prettier-2": "npm:prettier@^2", "serve": "14.2.1", "shiki": "0.14.7", "tsup": "8.0.2" diff --git a/packages/embed/tsconfig.json b/packages/embed/tsconfig.json index 6836d362..d33d3889 100644 --- a/packages/embed/tsconfig.json +++ b/packages/embed/tsconfig.json @@ -5,7 +5,7 @@ "outDir": "./dist", "declaration": true, "composite": true, - "sourceMap": false, + "sourceMap": true, "lib": ["es2021", "dom"], "target": "es2021", "emitDecoratorMetadata": false diff --git a/turbo.json b/turbo.json index aa568ee4..40563492 100644 --- a/turbo.json +++ b/turbo.json @@ -18,7 +18,7 @@ "dist/**" ] }, - "@snipcode/core#build": { + "@snipcode/backend#build": { "dependsOn": [ "^build" ], @@ -35,13 +35,24 @@ ], "env": [ "NODE_ENV", - "DATABASE_URL" + "DATABASE_URL", + "SENTRY_ENABLED", + "SENTRY_DSN", + "APP_VERSION", + "ADMIN_PASSWORD", + "JWT_SECRET" ] }, "@snipcode/domain#build": { "dependsOn": [ "^build", "prebuild" + ], + "outputs": [ + "dist/**" + ], + "env": [ + "DATABASE_URL" ] }, "@snipcode/web#build": { @@ -66,7 +77,28 @@ ], "env": [ "NODE_ENV", - "NEXT_PUBLIC_SERVER_URL" + "NEXT_PUBLIC_SERVER_URL", + "NEXT_PUBLIC_APP_URL", + "NEXT_PUBLIC_APP_ENV" + ] + }, + "@snipcode/embed#build": { + "dependsOn": [ + "^build" + ], + "outputs": [ + "dist/**" + ], + "env": [ + "EMBED_JS_URL", + "EMBED_STYLE_URL", + "WEB_APP_URL", + "WEB_APP_SNIPPET_VIEW_URL" + ] + }, + "@snipcode/backend#test": { + "dependsOn": [ + "@snipcode/domain#test" ] }, "test": { diff --git a/yarn.lock b/yarn.lock index 25c909cf..8e96ce6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4514,6 +4514,7 @@ __metadata: "@types/express": "npm:4.17.21" express: "npm:4.19.1" nodemon: "npm:2.0.22" + prettier-2: "npm:prettier@^2" serve: "npm:14.2.1" shiki: "npm:0.14.7" tsup: "npm:8.0.2" @@ -8227,6 +8228,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:16.0.3": + version: 16.0.3 + resolution: "dotenv@npm:16.0.3" + checksum: 10/d6788c8e40b35ad9a9ca29249dccf37fa6b3ad26700fcbc87f2f41101bf914f5193a04e36a3d23de70b1dcb8e5d5a3b21e151debace2c4cd08d868be500a1b29 + languageName: node + linkType: hard + "dotenv@npm:16.4.5, dotenv@npm:^16.3.0": version: 16.4.5 resolution: "dotenv@npm:16.4.5" @@ -8696,6 +8704,17 @@ __metadata: languageName: node linkType: hard +"eslint-config-turbo@npm:2.0.3": + version: 2.0.3 + resolution: "eslint-config-turbo@npm:2.0.3" + dependencies: + eslint-plugin-turbo: "npm:2.0.3" + peerDependencies: + eslint: ">6.6.0" + checksum: 10/55f8169dfdc82308c3eb176b5c45fb3cf0cee40e390a837bd4a8db0fe83070c5f50af806d3c47f0ed534a6668519fedcf67bc1bf4033684d5bf4f185238b0a9e + languageName: node + linkType: hard + "eslint-import-resolver-node@npm:^0.3.6, eslint-import-resolver-node@npm:^0.3.9": version: 0.3.9 resolution: "eslint-import-resolver-node@npm:0.3.9" @@ -8913,6 +8932,17 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-turbo@npm:2.0.3": + version: 2.0.3 + resolution: "eslint-plugin-turbo@npm:2.0.3" + dependencies: + dotenv: "npm:16.0.3" + peerDependencies: + eslint: ">6.6.0" + checksum: 10/4ae4896be69cacca0c5b93fd4688b8feca74dc86910f275ce64dde9f5c58e55b99f90c938a97e7b7cce7f81e1684878b5d4e9e7904b82ab0707fde38a6c62b9c + languageName: node + linkType: hard + "eslint-plugin-typescript-sort-keys@npm:3.2.0": version: 3.2.0 resolution: "eslint-plugin-typescript-sort-keys@npm:3.2.0" @@ -13922,6 +13952,15 @@ __metadata: languageName: node linkType: hard +"prettier-2@npm:prettier@^2, prettier@npm:^2.7.1": + version: 2.8.8 + resolution: "prettier@npm:2.8.8" + bin: + prettier: bin-prettier.js + checksum: 10/00cdb6ab0281f98306cd1847425c24cbaaa48a5ff03633945ab4c701901b8e96ad558eb0777364ffc312f437af9b5a07d0f45346266e8245beaf6247b9c62b24 + languageName: node + linkType: hard + "prettier-linter-helpers@npm:^1.0.0": version: 1.0.0 resolution: "prettier-linter-helpers@npm:1.0.0" @@ -13940,15 +13979,6 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^2.7.1": - version: 2.8.8 - resolution: "prettier@npm:2.8.8" - bin: - prettier: bin-prettier.js - checksum: 10/00cdb6ab0281f98306cd1847425c24cbaaa48a5ff03633945ab4c701901b8e96ad558eb0777364ffc312f437af9b5a07d0f45346266e8245beaf6247b9c62b24 - languageName: node - linkType: hard - "pretty-format@npm:^27.0.2": version: 27.5.1 resolution: "pretty-format@npm:27.5.1" @@ -15325,6 +15355,7 @@ __metadata: dotenv-cli: "npm:7.4.2" eslint: "npm:8.56.0" eslint-config-prettier: "npm:9.1.0" + eslint-config-turbo: "npm:2.0.3" eslint-plugin-import: "npm:2.29.1" eslint-plugin-jest: "npm:27.9.0" eslint-plugin-prettier: "npm:5.1.3"