because I got bored of customising my CV for every job
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

test(server): extract inline GraphQL to .graphql files and import in tests

+167 -278
+9 -26
apps/server/test/app-integration.e2e-spec.ts
··· 1 1 import type { INestApplication } from "@nestjs/common"; 2 - import request from "supertest"; 2 + import { 3 + BASIC_ME_QUERY, 4 + HEALTH_QUERY, 5 + HELLO_QUERY, 6 + INTROSPECTION_QUERY, 7 + } from "./queries/load-queries"; 3 8 import { makeUnauthenticatedRequest, setupTestApp } from "./test-utils"; 4 - import { HELLO_QUERY, HEALTH_QUERY, INTROSPECTION_QUERY } from "./queries/load-queries"; 5 9 6 10 describe("App Integration Tests (e2e)", () => { 7 11 let app: INestApplication; ··· 58 62 59 63 describe("Error Handling", () => { 60 64 it("should return error for invalid token", async () => { 61 - const basicMeQuery = ` 62 - query Me { 63 - me { 64 - id 65 - email 66 - name 67 - } 68 - } 69 - `; 70 - 71 - const response = await request(app.getHttpServer()) 72 - .post("/graphql") 65 + const response = await makeUnauthenticatedRequest(app) 73 66 .set("Authorization", "Bearer invalid-token") 74 67 .send({ 75 - query: basicMeQuery, 68 + query: BASIC_ME_QUERY, 76 69 }) 77 70 .expect(200); 78 71 ··· 81 74 }); 82 75 83 76 it("should return error for missing authorization header", async () => { 84 - const basicMeQuery = ` 85 - query Me { 86 - me { 87 - id 88 - email 89 - name 90 - } 91 - } 92 - `; 93 - 94 77 const response = await makeUnauthenticatedRequest(app) 95 78 .send({ 96 - query: basicMeQuery, 79 + query: BASIC_ME_QUERY, 97 80 }) 98 81 .expect(200); 99 82
+29 -31
apps/server/test/auth-integration.e2e-spec.ts
··· 1 1 import type { INestApplication } from "@nestjs/common"; 2 - import request from "supertest"; 3 - import { createTestUser, makeAuthenticatedRequest, makeUnauthenticatedRequest, setupTestApp, type TestUser } from "./test-utils"; 4 - import { REGISTER_MUTATION, LOGIN_MUTATION, BASIC_ME_QUERY, ME_WITH_ORGANIZATIONS_QUERY, COMPLEX_ME_QUERY } from "./queries/load-queries"; 2 + import { 3 + BASIC_ME_QUERY, 4 + COMPLEX_ME_QUERY, 5 + LOGIN_MUTATION, 6 + ME_WITH_ORGANIZATIONS_QUERY, 7 + REGISTER_MUTATION, 8 + } from "./queries/load-queries"; 9 + import { 10 + createTestUser, 11 + makeAuthenticatedRequest, 12 + makeUnauthenticatedRequest, 13 + setupTestApp, 14 + type TestUser, 15 + } from "./test-utils"; 5 16 6 17 describe("Auth Integration Tests (e2e)", () => { 7 18 let app: INestApplication; ··· 32 43 33 44 expect(registerResponse.body.data.register).toBeDefined(); 34 45 expect(registerResponse.body.data.register.access_token).toBeDefined(); 35 - expect(registerResponse.body.data.register.user.email).toBe(newTestUser.email); 36 - expect(registerResponse.body.data.register.user.name).toBe(newTestUser.name); 46 + expect(registerResponse.body.data.register.user.email).toBe( 47 + newTestUser.email, 48 + ); 49 + expect(registerResponse.body.data.register.user.name).toBe( 50 + newTestUser.name, 51 + ); 37 52 38 53 const { access_token } = registerResponse.body.data.register; 39 54 ··· 123 138 .expect(200); 124 139 125 140 expect(response.body.errors).toBeDefined(); 126 - expect(response.body.errors[0].message).toContain("User with this email already exists"); 141 + expect(response.body.errors[0].message).toContain( 142 + "User with this email already exists", 143 + ); 127 144 }); 128 145 }); 129 146 ··· 179 196 180 197 // Verify organizations don't have description field (not requested) 181 198 if (response.body.data.me.organizations.length > 0) { 182 - expect(response.body.data.me.organizations[0].description).toBeUndefined(); 199 + expect( 200 + response.body.data.me.organizations[0].description, 201 + ).toBeUndefined(); 183 202 } 184 203 }); 185 204 ··· 224 243 225 244 describe("Error Handling", () => { 226 245 it("should return error for invalid token", async () => { 227 - const basicMeQuery = ` 228 - query Me { 229 - me { 230 - id 231 - email 232 - name 233 - } 234 - } 235 - `; 236 - 237 - const response = await request(app.getHttpServer()) 238 - .post("/graphql") 246 + const response = await makeUnauthenticatedRequest(app) 239 247 .set("Authorization", "Bearer invalid-token") 240 248 .send({ 241 - query: basicMeQuery, 249 + query: BASIC_ME_QUERY, 242 250 }) 243 251 .expect(200); 244 252 ··· 247 255 }); 248 256 249 257 it("should return error for missing authorization header", async () => { 250 - const basicMeQuery = ` 251 - query Me { 252 - me { 253 - id 254 - email 255 - name 256 - } 257 - } 258 - `; 259 - 260 258 const response = await makeUnauthenticatedRequest(app) 261 259 .send({ 262 - query: basicMeQuery, 260 + query: BASIC_ME_QUERY, 263 261 }) 264 262 .expect(200); 265 263
+29 -85
apps/server/test/auth.e2e-spec.ts
··· 3 3 import { Test, type TestingModule } from "@nestjs/testing"; 4 4 import request from "supertest"; 5 5 import { AppModule } from "../src/modules/app.module"; 6 + import { 7 + BASIC_ME_QUERY, 8 + LOGIN_MUTATION, 9 + REGISTER_MUTATION, 10 + } from "./queries/load-queries"; 6 11 7 12 describe("Authentication Flow (e2e)", () => { 8 13 let app: INestApplication; ··· 45 50 }; 46 51 47 52 // Step 1: Register a new user 48 - const registerMutation = ` 49 - mutation Register($name: String!, $email: String!, $password: String!) { 50 - register(name: $name, email: $email, password: $password) { 51 - access_token 52 - user { 53 - id 54 - email 55 - name 56 - } 57 - } 58 - } 59 - `; 60 - 61 - const registerResponse = await request(app.getHttpServer()).post("/graphql").send({ 62 - query: registerMutation, 63 - variables: testUser, 64 - }); 53 + const registerResponse = await request(app.getHttpServer()) 54 + .post("/graphql") 55 + .send({ 56 + query: REGISTER_MUTATION, 57 + variables: testUser, 58 + }); 65 59 66 60 // Debug the response if it fails 67 - if (registerResponse.status !== 200 || !registerResponse.body.data?.register) { 68 - throw new Error(`Registration failed: ${JSON.stringify(registerResponse.body)}`); 61 + if ( 62 + registerResponse.status !== 200 || 63 + !registerResponse.body.data?.register 64 + ) { 65 + throw new Error( 66 + `Registration failed: ${JSON.stringify(registerResponse.body)}`, 67 + ); 69 68 } 70 69 71 70 expect(registerResponse.body.data.register).toBeDefined(); 72 71 expect(registerResponse.body.data.register.access_token).toBeDefined(); 73 - expect(registerResponse.body.data.register.user.email).toBe(testUser.email); 72 + expect(registerResponse.body.data.register.user.email).toBe( 73 + testUser.email, 74 + ); 74 75 expect(registerResponse.body.data.register.user.name).toBe(testUser.name); 75 76 76 77 const { access_token } = registerResponse.body.data.register; 77 78 78 79 // Step 2: Login with the registered user 79 - const loginMutation = ` 80 - mutation Login($email: String!, $password: String!) { 81 - login(email: $email, password: $password) { 82 - access_token 83 - user { 84 - id 85 - email 86 - name 87 - } 88 - } 89 - } 90 - `; 91 - 92 80 const loginResponse = await request(app.getHttpServer()) 93 81 .post("/graphql") 94 82 .send({ 95 - query: loginMutation, 83 + query: LOGIN_MUTATION, 96 84 variables: { 97 85 email: testUser.email, 98 86 password: testUser.password, ··· 106 94 expect(loginResponse.body.data.login.user.name).toBe(testUser.name); 107 95 108 96 // Step 3: Use the token to get current user info 109 - const meQuery = ` 110 - query Me { 111 - me { 112 - id 113 - email 114 - name 115 - } 116 - } 117 - `; 118 - 119 97 const meResponse = await request(app.getHttpServer()) 120 98 .post("/graphql") 121 99 .set("Authorization", `Bearer ${access_token}`) 122 100 .send({ 123 - query: meQuery, 101 + query: BASIC_ME_QUERY, 124 102 }) 125 103 .expect(200); 126 104 ··· 131 109 }); 132 110 133 111 it("should fail me query without authentication", async () => { 134 - const meQuery = ` 135 - query Me { 136 - me { 137 - id 138 - email 139 - name 140 - } 141 - } 142 - `; 143 - 144 112 const response = await request(app.getHttpServer()) 145 113 .post("/graphql") 146 114 .send({ 147 - query: meQuery, 115 + query: BASIC_ME_QUERY, 148 116 }) 149 117 .expect(200); 150 118 ··· 190 158 }; 191 159 192 160 // Register the first user 193 - const firstRegisterMutation = ` 194 - mutation Register($name: String!, $email: String!, $password: String!) { 195 - register(name: $name, email: $email, password: $password) { 196 - access_token 197 - user { 198 - id 199 - email 200 - name 201 - } 202 - } 203 - } 204 - `; 205 - 206 161 await request(app.getHttpServer()) 207 162 .post("/graphql") 208 163 .send({ 209 - query: firstRegisterMutation, 164 + query: REGISTER_MUTATION, 210 165 variables: firstUser, 211 166 }) 212 167 .expect(200); ··· 218 173 password: "password123", 219 174 }; 220 175 221 - const registerMutation = ` 222 - mutation Register($name: String!, $email: String!, $password: String!) { 223 - register(name: $name, email: $email, password: $password) { 224 - access_token 225 - user { 226 - id 227 - email 228 - name 229 - } 230 - } 231 - } 232 - `; 233 - 234 176 const response = await request(app.getHttpServer()) 235 177 .post("/graphql") 236 178 .send({ 237 - query: registerMutation, 179 + query: REGISTER_MUTATION, 238 180 variables: testUser, 239 181 }) 240 182 .expect(200); 241 183 242 184 expect(response.body.errors).toBeDefined(); 243 - expect(response.body.errors[0].message).toContain("User with this email already exists"); 185 + expect(response.body.errors[0].message).toContain( 186 + "User with this email already exists", 187 + ); 244 188 }); 245 189 }); 246 190 });
+28 -99
apps/server/test/graphql-optimization.e2e-spec.ts
··· 3 3 import { Test, type TestingModule } from "@nestjs/testing"; 4 4 import request from "supertest"; 5 5 import { AppModule } from "../src/modules/app.module"; 6 + import { 7 + BASIC_ME_QUERY, 8 + ME_WITH_ORGANIZATIONS_PARTIAL_QUERY, 9 + ME_WITH_ORGANIZATIONS_QUERY, 10 + REGISTER_MUTATION, 11 + } from "./queries/load-queries"; 6 12 7 13 describe("GraphQL Query Optimization (e2e)", () => { 8 14 let app: INestApplication; ··· 45 51 }; 46 52 47 53 // Register user 48 - const registerMutation = ` 49 - mutation Register($name: String!, $email: String!, $password: String!) { 50 - register(name: $name, email: $email, password: $password) { 51 - access_token 52 - user { 53 - id 54 - email 55 - name 56 - } 57 - } 58 - } 59 - `; 60 - 61 - const registerResponse = await request(app.getHttpServer()).post("/graphql").send({ 62 - query: registerMutation, 63 - variables: testUser, 64 - }); 54 + const registerResponse = await request(app.getHttpServer()) 55 + .post("/graphql") 56 + .send({ 57 + query: REGISTER_MUTATION, 58 + variables: testUser, 59 + }); 65 60 66 61 // Debug the response if it fails 67 - if (registerResponse.status !== 200 || !registerResponse.body.data?.register) { 68 - throw new Error(`Registration failed: ${JSON.stringify(registerResponse.body)}`); 62 + if ( 63 + registerResponse.status !== 200 || 64 + !registerResponse.body.data?.register 65 + ) { 66 + throw new Error( 67 + `Registration failed: ${JSON.stringify(registerResponse.body)}`, 68 + ); 69 69 } 70 70 71 71 accessToken = registerResponse.body.data.register.access_token; ··· 78 78 79 79 describe("Me Query Optimization", () => { 80 80 it("should return basic user info without loading organizations", async () => { 81 - const basicMeQuery = ` 82 - query Me { 83 - me { 84 - id 85 - email 86 - name 87 - } 88 - } 89 - `; 90 - 91 81 const response = await request(app.getHttpServer()) 92 82 .post("/graphql") 93 83 .set("Authorization", `Bearer ${accessToken}`) 94 84 .send({ 95 - query: basicMeQuery, 85 + query: BASIC_ME_QUERY, 96 86 }) 97 87 .expect(200); 98 88 ··· 107 97 }); 108 98 109 99 it("should load organizations when explicitly requested", async () => { 110 - const meWithOrganizationsQuery = ` 111 - query Me { 112 - me { 113 - id 114 - email 115 - name 116 - organizations { 117 - id 118 - name 119 - description 120 - } 121 - } 122 - } 123 - `; 124 - 125 100 const response = await request(app.getHttpServer()) 126 101 .post("/graphql") 127 102 .set("Authorization", `Bearer ${accessToken}`) 128 103 .send({ 129 - query: meWithOrganizationsQuery, 104 + query: ME_WITH_ORGANIZATIONS_QUERY, 130 105 }) 131 106 .expect(200); 132 107 ··· 142 117 }); 143 118 144 119 it("should handle partial organization field requests", async () => { 145 - const partialOrganizationsQuery = ` 146 - query Me { 147 - me { 148 - id 149 - name 150 - organizations { 151 - id 152 - name 153 - } 154 - } 155 - } 156 - `; 157 - 158 120 const response = await request(app.getHttpServer()) 159 121 .post("/graphql") 160 122 .set("Authorization", `Bearer ${accessToken}`) 161 123 .send({ 162 - query: partialOrganizationsQuery, 124 + query: ME_WITH_ORGANIZATIONS_PARTIAL_QUERY, 163 125 }) 164 126 .expect(200); 165 127 ··· 172 134 173 135 // Verify organizations don't have description field (not requested) 174 136 if (response.body.data.me.organizations.length > 0) { 175 - expect(response.body.data.me.organizations[0].description).toBeUndefined(); 137 + expect( 138 + response.body.data.me.organizations[0].description, 139 + ).toBeUndefined(); 176 140 } 177 141 }); 178 142 179 143 it("should return empty organizations array for user with no organizations", async () => { 180 - const meWithOrganizationsQuery = ` 181 - query Me { 182 - me { 183 - id 184 - email 185 - name 186 - organizations { 187 - id 188 - name 189 - description 190 - } 191 - } 192 - } 193 - `; 194 - 195 144 const response = await request(app.getHttpServer()) 196 145 .post("/graphql") 197 146 .set("Authorization", `Bearer ${accessToken}`) 198 147 .send({ 199 - query: meWithOrganizationsQuery, 148 + query: ME_WITH_ORGANIZATIONS_QUERY, 200 149 }) 201 150 .expect(200); 202 151 ··· 279 228 280 229 describe("Error Handling", () => { 281 230 it("should return error for invalid token", async () => { 282 - const basicMeQuery = ` 283 - query Me { 284 - me { 285 - id 286 - email 287 - name 288 - } 289 - } 290 - `; 291 - 292 231 const response = await request(app.getHttpServer()) 293 232 .post("/graphql") 294 233 .set("Authorization", "Bearer invalid-token") 295 234 .send({ 296 - query: basicMeQuery, 235 + query: BASIC_ME_QUERY, 297 236 }) 298 237 .expect(200); 299 238 ··· 302 241 }); 303 242 304 243 it("should return error for missing authorization header", async () => { 305 - const basicMeQuery = ` 306 - query Me { 307 - me { 308 - id 309 - email 310 - name 311 - } 312 - } 313 - `; 314 - 315 244 const response = await request(app.getHttpServer()) 316 245 .post("/graphql") 317 246 .send({ 318 - query: basicMeQuery, 247 + query: BASIC_ME_QUERY, 319 248 }) 320 249 .expect(200); 321 250
+6
apps/server/test/queries/create-company-mutation.graphql
··· 1 + mutation CreateCompany($name: String!) { 2 + createCompany(name: $name) { 3 + id 4 + name 5 + } 6 + }
+51 -21
apps/server/test/queries/load-queries.ts
··· 1 - import { readFileSync } from 'fs'; 2 - import { join } from 'path'; 1 + import { readFileSync } from "node:fs"; 2 + import { join } from "node:path"; 3 3 4 4 /** 5 5 * Simple utility to read GraphQL files and return their content as strings 6 6 */ 7 - export const readGraphQLFile = (filename: string): string => 8 - readFileSync(join(__dirname, filename), 'utf-8'); 7 + export const readGraphQLFile = (filename: string): string => 8 + readFileSync(join(__dirname, filename), "utf-8"); 9 9 10 10 // Auth queries 11 - export const REGISTER_MUTATION = readGraphQLFile('register-mutation.graphql'); 12 - export const LOGIN_MUTATION = readGraphQLFile('login-mutation.graphql'); 13 - export const BASIC_ME_QUERY = readGraphQLFile('basic-me-query.graphql'); 14 - export const ME_WITH_ORGANIZATIONS_QUERY = readGraphQLFile('me-with-organizations-query.graphql'); 15 - export const COMPLEX_ME_QUERY = readGraphQLFile('complex-me-query.graphql'); 11 + export const REGISTER_MUTATION = readGraphQLFile("register-mutation.graphql"); 12 + export const LOGIN_MUTATION = readGraphQLFile("login-mutation.graphql"); 13 + export const BASIC_ME_QUERY = readGraphQLFile("basic-me-query.graphql"); 14 + export const ME_WITH_ORGANIZATIONS_QUERY = readGraphQLFile( 15 + "me-with-organizations-query.graphql", 16 + ); 17 + export const ME_WITH_ORGANIZATIONS_PARTIAL_QUERY = readGraphQLFile( 18 + "me-with-organizations-partial-query.graphql", 19 + ); 20 + export const COMPLEX_ME_QUERY = readGraphQLFile("complex-me-query.graphql"); 16 21 17 22 // Job experience queries 18 - export const CREATE_JOB_EXPERIENCE_MUTATION = readGraphQLFile('create-job-experience-mutation.graphql'); 19 - export const UPDATE_JOB_EXPERIENCE_MUTATION = readGraphQLFile('update-job-experience-mutation.graphql'); 20 - export const DELETE_JOB_EXPERIENCE_MUTATION = readGraphQLFile('delete-job-experience-mutation.graphql'); 21 - export const MY_EMPLOYMENT_HISTORY_QUERY = readGraphQLFile('my-employment-history-query.graphql'); 22 - export const MY_EMPLOYMENT_HISTORY_SIMPLE_QUERY = readGraphQLFile('my-employment-history-simple-query.graphql'); 23 - export const ALL_COMPANIES_QUERY = readGraphQLFile('all-companies-query.graphql'); 24 - export const ALL_SKILLS_QUERY = readGraphQLFile('all-skills-query.graphql'); 25 - export const ALL_ROLES_QUERY = readGraphQLFile('all-roles-query.graphql'); 26 - export const ALL_LEVELS_QUERY = readGraphQLFile('all-levels-query.graphql'); 23 + export const CREATE_JOB_EXPERIENCE_MUTATION = readGraphQLFile( 24 + "create-job-experience-mutation.graphql", 25 + ); 26 + export const UPDATE_JOB_EXPERIENCE_MUTATION = readGraphQLFile( 27 + "update-job-experience-mutation.graphql", 28 + ); 29 + export const DELETE_JOB_EXPERIENCE_MUTATION = readGraphQLFile( 30 + "delete-job-experience-mutation.graphql", 31 + ); 32 + export const MY_EMPLOYMENT_HISTORY_QUERY = readGraphQLFile( 33 + "my-employment-history-query.graphql", 34 + ); 35 + export const MY_EMPLOYMENT_HISTORY_SIMPLE_QUERY = readGraphQLFile( 36 + "my-employment-history-simple-query.graphql", 37 + ); 38 + export const ALL_COMPANIES_QUERY = readGraphQLFile( 39 + "all-companies-query.graphql", 40 + ); 41 + export const ALL_SKILLS_QUERY = readGraphQLFile("all-skills-query.graphql"); 42 + export const ALL_ROLES_QUERY = readGraphQLFile("all-roles-query.graphql"); 43 + export const ALL_LEVELS_QUERY = readGraphQLFile("all-levels-query.graphql"); 44 + 45 + // Additional queries extracted from inline usage 46 + export const CREATE_COMPANY_MUTATION = readGraphQLFile( 47 + "create-company-mutation.graphql", 48 + ); 49 + export const UPDATE_JOB_EXPERIENCE_DETAILED_MUTATION = readGraphQLFile( 50 + "update-job-experience-mutation.graphql", 51 + ); 52 + export const MY_EMPLOYMENT_HISTORY_MINIMAL = readGraphQLFile( 53 + "my-employment-history-minimal.graphql", 54 + ); 27 55 28 56 // App queries 29 - export const HELLO_QUERY = readGraphQLFile('hello-query.graphql'); 30 - export const HEALTH_QUERY = readGraphQLFile('health-query.graphql'); 31 - export const INTROSPECTION_QUERY = readGraphQLFile('introspection-query.graphql'); 57 + export const HELLO_QUERY = readGraphQLFile("hello-query.graphql"); 58 + export const HEALTH_QUERY = readGraphQLFile("health-query.graphql"); 59 + export const INTROSPECTION_QUERY = readGraphQLFile( 60 + "introspection-query.graphql", 61 + );
+10
apps/server/test/queries/me-with-organizations-partial-query.graphql
··· 1 + query Me { 2 + me { 3 + id 4 + name 5 + organizations { 6 + id 7 + name 8 + } 9 + } 10 + }
+5
apps/server/test/queries/my-employment-history-minimal.graphql
··· 1 + query MeJobExperience { 2 + myEmploymentHistory { 3 + id 4 + } 5 + }
-16
apps/server/test/queries/update-job-experience-mutation.graphql
··· 9 9 description: $description 10 10 ) { 11 11 id 12 - startDate 13 - endDate 14 12 description 15 13 company { 16 14 id 17 15 name 18 16 } 19 - role { 20 - id 21 - name 22 - } 23 - level { 24 - id 25 - name 26 - } 27 - skills { 28 - id 29 - name 30 - } 31 - createdAt 32 - updatedAt 33 17 } 34 18 }