From 223c2ce117b46fa9c95cafcd4d3b9aa9a1e3d327 Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Mon, 19 Jan 2026 18:34:39 +0530 Subject: [PATCH 1/4] test: add unit tests for routes and controllers for detail page --- tests/constants/application-data.js | 65 +++++++++++++ .../controllers/applications/detail-test.js | 91 +++++++++++++++++++ tests/unit/routes/applications/detail-test.js | 31 +++++-- 3 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 tests/constants/application-data.js create mode 100644 tests/unit/controllers/applications/detail-test.js diff --git a/tests/constants/application-data.js b/tests/constants/application-data.js new file mode 100644 index 00000000..435a7108 --- /dev/null +++ b/tests/constants/application-data.js @@ -0,0 +1,65 @@ +export const APPLICATIONS_DATA = { + id: '2MzNJtwGL3D28WeC7yUI', + userId: 'SoaTFu1SnU7HVvWjkR7Z', + biodata: { firstName: 'John', lastName: 'Doe' }, + location: { + city: 'Patna', + state: 'Bihar', + country: 'India', + }, + professional: { + institution: 'MIT', + skills: + 'JavaScript, Node.js, React, Next, Ember.js, Typescript, Java, Springboot, Docker, Azure, AWS, GenAI, AI Agents, Langchain, Redis, Postgresql, MongoDB, WebSockets', + }, + intro: { + introduction: + 'I am a passionate developer with 5 years of experience. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + funFact: + 'I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users.I once built a full-stack application in 48 hours during a hackathon. The project went on to win first place and is now used by over 10,000 users. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + forFun: + 'I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking.I love coding, reading tech blogs, and contributing to open source projects. In my free time, I enjoy playing guitar and hiking. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + whyRds: + 'I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects.I am excited to join Real Dev Squad because of its commitment to open source and community-driven development. I believe in the mission and want to contribute to meaningful projects. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + numberOfHours: 20, + }, + foundFrom: 'LinkedIn', + role: 'developer', + imageUrl: + 'https://res.cloudinary.com/imgprc/image/upload/v1767280230/profile/nEYwqHm8vGoZhh1j9PbF/no8jkcirgj3sb9phfm20.jpg', + socialLink: { + github: 'johndoe', + linkedin: 'johndoe', + twitter: 'Johndoe', + peerlist: 'johndoe', + instagram: 'johndoe', + dribbble: 'johndoe', + behance: 'johndoe', + }, + feedback: [ + { + status: 'accepted', + feedback: '', + reviewerName: 'Ankush', + createdAt: '2026-01-14T15:37:10.991Z', + }, + { + status: 'changes_requested', + feedback: 'Please follow requirements for the profile picture', + reviewerName: 'Prakash', + createdAt: '2026-01-13T12:37:10.991Z', + }, + { + status: 'rejected', + feedback: 'lorem', + reviewerName: 'Tejas', + createdAt: '2026-01-11T10:37:10.991Z', + }, + ], + score: 250, + status: 'accepted', + createdAt: '2026-01-14T18:37:10.991Z', + nudgeCount: 10, + isNew: false, + notFound: false, +}; diff --git a/tests/unit/controllers/applications/detail-test.js b/tests/unit/controllers/applications/detail-test.js new file mode 100644 index 00000000..de600713 --- /dev/null +++ b/tests/unit/controllers/applications/detail-test.js @@ -0,0 +1,91 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'website-www/tests/helpers'; +import { APPLICATIONS_DATA } from 'website-www/tests/constants/application-data'; + +module('Unit | Controller | applications/detail', function (hooks) { + setupTest(hooks); + + hooks.beforeEach(function () { + this.controller = this.owner.lookup('controller:applications/detail'); + }); + + test('application details controller exists', function (assert) { + assert.ok(this.controller, 'Controller for application detail exists!'); + }); + + test('isAdmin correctly identifies super_user role', function (assert) { + this.controller.model = { currentUser: { roles: { super_user: true } } }; + assert.true(this.controller.isAdmin, 'True when super_user'); + + this.controller.model = { currentUser: { roles: { super_user: false } } }; + assert.false(this.controller.isAdmin, 'False when not super_user'); + }); + + test('isApplicant correctly identifies application owner', function (assert) { + const userId = APPLICATIONS_DATA.userId; + this.controller.model = { + currentUser: { id: userId }, + application: { userId }, + }; + assert.true(this.controller.isApplicant, 'True when IDs match'); + + this.controller.model = { + currentUser: { id: userId }, + application: { userId: 'other' }, + }; + assert.false(this.controller.isApplicant, 'False when IDs mismatch'); + }); + + test('canAccessApplication correctly returns application access', function (assert) { + this.controller.model = { + currentUser: { roles: { super_user: true } }, + application: { userId: 'other' }, + }; + assert.true(this.controller.canAccessApplication, 'Admin access'); + + this.controller.model = { + currentUser: { id: 'user1' }, + application: { userId: 'user1' }, + }; + assert.true(this.controller.canAccessApplication, 'Applicant access'); + + this.controller.model = { + currentUser: { id: 'user1', roles: { super_user: false } }, + application: { userId: 'user2' }, + }; + assert.false(this.controller.canAccessApplication, 'No access'); + }); + + test('aboutYouSections getter formats the data correctly', function (assert) { + this.controller.model = { application: APPLICATIONS_DATA }; + + const expected = [ + { label: 'Introduction', value: APPLICATIONS_DATA.intro.introduction }, + { label: 'Fun Fact', value: APPLICATIONS_DATA.intro.funFact }, + { label: 'For Fun', value: APPLICATIONS_DATA.intro.forFun }, + { label: 'Why Join Us', value: APPLICATIONS_DATA.intro.whyRds }, + ]; + + assert.deepEqual( + this.controller.aboutYouSections, + expected, + 'Formatted correctly', + ); + }); + + test('hasFeedback correctly identifies feedback presence', function (assert) { + this.controller.model = { application: APPLICATIONS_DATA }; + assert.true(this.controller.hasFeedback, 'True when feedback present'); + + this.controller.model = { application: { feedback: [] } }; + assert.false(this.controller.hasFeedback, 'False when empty'); + }); + + test('showAdminMessage correctly maps application status', function (assert) { + this.controller.model = { application: { status: 'pending' } }; + assert.ok(this.controller.showAdminMessage.includes('reviewing')); + + this.controller.model = { application: { status: 'accepted' } }; + assert.ok(this.controller.showAdminMessage.includes('approved')); + }); +}); diff --git a/tests/unit/routes/applications/detail-test.js b/tests/unit/routes/applications/detail-test.js index 3587c2fe..8335e429 100644 --- a/tests/unit/routes/applications/detail-test.js +++ b/tests/unit/routes/applications/detail-test.js @@ -6,7 +6,7 @@ import { SELF_USER_PROFILE_URL, } from 'website-www/constants/apis'; -module.skip('Unit | Route | applications/detail', function (hooks) { +module('Unit | Route | applications/detail', function (hooks) { setupTest(hooks); hooks.beforeEach(function () { @@ -28,13 +28,12 @@ module.skip('Unit | Route | applications/detail', function (hooks) { test('fetches application by id successfully', async function (assert) { const mockApplication = { id: '123', userId: 'user1' }; + const mockUser = { first_name: 'John' }; const applicationId = '123'; this.fetchStub .onCall(0) - .resolves( - new Response(JSON.stringify({ first_name: 'John' }), { status: 200 }), - ); + .resolves(new Response(JSON.stringify(mockUser), { status: 200 })); this.fetchStub.onCall(1).resolves( new Response(JSON.stringify({ application: mockApplication }), { @@ -44,7 +43,11 @@ module.skip('Unit | Route | applications/detail', function (hooks) { const result = await this.route.model({ id: applicationId }); - assert.deepEqual(result, mockApplication, 'Returns application from API'); + assert.deepEqual( + result, + { application: mockApplication, currentUser: mockUser }, + 'Returns application and currentUser from API', + ); assert.ok( this.fetchStub.firstCall.calledWith( SELF_USER_PROFILE_URL, @@ -66,7 +69,11 @@ module.skip('Unit | Route | applications/detail', function (hooks) { const result = await this.route.model({ id: '123' }); - assert.strictEqual(result, null, 'Returns null for 401'); + assert.deepEqual( + result, + { application: null, currentUser: null }, + 'Returns null object for 401', + ); assert.ok(this.route.toast.error.calledOnce, 'Error toast is displayed'); }); @@ -80,7 +87,11 @@ module.skip('Unit | Route | applications/detail', function (hooks) { const result = await this.route.model({ id: '123' }); - assert.strictEqual(result, null, 'Returns null for 404'); + assert.deepEqual( + result, + { application: null, currentUser: null }, + 'Returns null object for 404', + ); assert.ok( this.route.toast.error.calledOnce, 'Error toast is displayed for 404', @@ -97,7 +108,11 @@ module.skip('Unit | Route | applications/detail', function (hooks) { const result = await this.route.model({ id: '123' }); - assert.strictEqual(result, null, 'Returns null on error'); + assert.deepEqual( + result, + { application: null, currentUser: null }, + 'Returns null object on error', + ); assert.ok(this.route.toast.error.calledOnce, 'Error toast is displayed'); }); }); From 8e6c36446ac7f4907ad114da024f5654fb38efbb Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Mon, 19 Jan 2026 19:13:36 +0530 Subject: [PATCH 2/4] test: add integration tests for application components --- .../application/detail-header-test.js | 61 +++++++++++++++++++ .../application/feedback-card-test.js | 45 ++++++++++++++ .../components/application/info-card-test.js | 46 ++++++++++++++ .../application/social-link-pill-test.js | 26 ++++++++ .../application/status-badge-test.js | 32 ++++++++++ 5 files changed, 210 insertions(+) create mode 100644 tests/integration/components/application/detail-header-test.js create mode 100644 tests/integration/components/application/feedback-card-test.js create mode 100644 tests/integration/components/application/info-card-test.js create mode 100644 tests/integration/components/application/social-link-pill-test.js create mode 100644 tests/integration/components/application/status-badge-test.js diff --git a/tests/integration/components/application/detail-header-test.js b/tests/integration/components/application/detail-header-test.js new file mode 100644 index 00000000..833d9d28 --- /dev/null +++ b/tests/integration/components/application/detail-header-test.js @@ -0,0 +1,61 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'website-www/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; +import { APPLICATIONS_DATA } from 'website-www/tests/constants/application-data'; + +module('Integration | Component | application/detail-header', function (hooks) { + setupRenderingTest(hooks); + + test('it renders application details correctly', async function (assert) { + this.set('application', APPLICATIONS_DATA); + this.set('isAdmin', false); + + await render(hbs` + + `); + + assert.dom('[data-test-user-name]').includesText('John Doe'); + assert.dom('[data-test-status-badge]').hasText('ACCEPTED'); + assert.dom('[data-test-score-value]').hasText('250'); + assert.dom('[data-test-social-link]').exists({ count: 7 }); + + assert.dom('[data-test-button="nudge-button"]').exists(); + assert.dom('[data-test-button="edit-button"]').exists(); + assert.dom('[data-test-button="navigate-button"]').doesNotExist(); + }); + + test('it renders admin actions correctly', async function (assert) { + this.set('application', APPLICATIONS_DATA); + this.set('isAdmin', true); + + await render(hbs` + + `); + + assert.dom('[data-test-button="navigate-button"]').exists(); + assert.dom('[data-test-button="nudge-button"]').doesNotExist(); + assert.dom('[data-test-button="edit-button"]').doesNotExist(); + }); + + test('it disables nudge button when status is not pending', async function (assert) { + const app = { ...APPLICATIONS_DATA, status: 'accepted' }; + this.set('application', app); + this.set('isAdmin', false); + + await render(hbs` + + `); + + assert.dom('[data-test-button="nudge-button"]').hasAttribute('disabled'); + }); +}); diff --git a/tests/integration/components/application/feedback-card-test.js b/tests/integration/components/application/feedback-card-test.js new file mode 100644 index 00000000..51d17688 --- /dev/null +++ b/tests/integration/components/application/feedback-card-test.js @@ -0,0 +1,45 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'website-www/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | application/feedback-card', function (hooks) { + setupRenderingTest(hooks); + + test('it renders feedback details correctly', async function (assert) { + this.set('feedback', { + status: 'accepted', + feedback: 'Great job!', + reviewerName: 'Ankush', + createdAt: '2026-01-14T15:37:10.991Z', + }); + + await render(hbs` + + `); + + assert.dom('[data-test-status-badge]').hasText('ACCEPTED'); + assert.dom('[data-test-feedback-text]').hasText('Great job!'); + assert.dom('[data-test-feedback-reviewer]').includesText('Ankush'); + assert + .dom('[data-test-feedback-date]') + .hasText(new Date('2026-01-14T15:37:10.991Z').toLocaleDateString()); + }); + + test('it renders N/A for missing date', async function (assert) { + await render(hbs` + + `); + + assert.dom('[data-test-feedback-date]').hasText('N/A'); + }); +}); diff --git a/tests/integration/components/application/info-card-test.js b/tests/integration/components/application/info-card-test.js new file mode 100644 index 00000000..4a06180a --- /dev/null +++ b/tests/integration/components/application/info-card-test.js @@ -0,0 +1,46 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'website-www/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | application/info-card', function (hooks) { + setupRenderingTest(hooks); + + test('it renders title and default sections correctly', async function (assert) { + this.set('sections', [ + { label: 'Intro', value: 'Value 1' }, + { label: 'Fact', value: 'Value 2' }, + ]); + + await render( + hbs``, + ); + + assert.dom('[data-test-info-card-title]').hasText('About'); + assert.dom('[data-test-info-item]').doesNotExist(); + assert.dom('[data-test-info-block]').exists({ count: 2 }); + assert.dom('.info-label').includesText('Intro'); + assert.dom('.info-value').includesText('Value 1'); + }); + + test('it renders grid sections correctly', async function (assert) { + this.set('sections', [ + { + type: 'grid', + items: [ + { label: 'Item 1', value: 'Value 1' }, + { label: 'Item 2', value: 'Value 2' }, + ], + }, + ]); + + await render( + hbs``, + ); + + assert.dom('[data-test-info-section]').exists(); + assert.dom('[data-test-info-item]').exists({ count: 2 }); + assert.dom('.info-label').includesText('Item 1'); + assert.dom('.info-value').includesText('Value 1'); + }); +}); diff --git a/tests/integration/components/application/social-link-pill-test.js b/tests/integration/components/application/social-link-pill-test.js new file mode 100644 index 00000000..4c754f95 --- /dev/null +++ b/tests/integration/components/application/social-link-pill-test.js @@ -0,0 +1,26 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'website-www/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module( + 'Integration | Component | application/social-link-pill', + function (hooks) { + setupRenderingTest(hooks); + + test('it renders the platform and links correctly', async function (assert) { + this.set('platform', 'GitHub'); + this.set('userName', 'testuser'); + + await render( + hbs``, + ); + + assert + .dom('[data-test-social-link]') + .hasAttribute('href', 'https://github.com/testuser'); + assert.dom('[data-test-social-link]').includesText('GitHub'); + assert.dom('[data-test-platform="GitHub"]').exists(); + }); + }, +); diff --git a/tests/integration/components/application/status-badge-test.js b/tests/integration/components/application/status-badge-test.js new file mode 100644 index 00000000..75fb346c --- /dev/null +++ b/tests/integration/components/application/status-badge-test.js @@ -0,0 +1,32 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'website-www/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | application/status-badge', function (hooks) { + setupRenderingTest(hooks); + + test('it renders the status in uppercase', async function (assert) { + await render(hbs``); + assert.dom('[data-test-status-badge]').hasText('ACCEPTED'); + + await render(hbs``); + assert.dom('[data-test-status-badge]').hasText('PENDING'); + + await render(hbs``); + assert.dom('[data-test-status-badge]').hasText('CHANGES REQUESTED'); + }); + + test('it applies the correct status class', async function (assert) { + await render(hbs``); + assert.dom('[data-test-status-badge]').hasClass('status-badge--accepted'); + + await render(hbs``); + assert.dom('[data-test-status-badge]').hasClass('status-badge--rejected'); + }); + + test('it fallbacks to PENDING for unknown status', async function (assert) { + await render(hbs``); + assert.dom('[data-test-status-badge]').hasText('PENDING'); + }); +}); From 21bdb58bfde92d9d476e1ec6c4a2fe495ca6ded3 Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Mon, 19 Jan 2026 20:56:11 +0530 Subject: [PATCH 3/4] fix: add more expectation and cleanup tests --- .../application/detail-header-test.js | 25 +++++++++++++ .../application/feedback-card-test.js | 13 +++++++ .../components/application/info-card-test.js | 36 ++++++++++--------- .../application/social-link-pill-test.js | 25 +++++++++++++ 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/tests/integration/components/application/detail-header-test.js b/tests/integration/components/application/detail-header-test.js index 833d9d28..1d3b732c 100644 --- a/tests/integration/components/application/detail-header-test.js +++ b/tests/integration/components/application/detail-header-test.js @@ -44,6 +44,16 @@ module('Integration | Component | application/detail-header', function (hooks) { assert.dom('[data-test-button="edit-button"]').doesNotExist(); }); + test('it handles partial location data correctly', async function (assert) { + this.set('application', { + location: { city: 'Mumbai', country: 'India' }, + }); + await render( + hbs``, + ); + assert.dom('[data-test-header-profile]').includesText('Mumbai, India'); + }); + test('it disables nudge button when status is not pending', async function (assert) { const app = { ...APPLICATIONS_DATA, status: 'accepted' }; this.set('application', app); @@ -58,4 +68,19 @@ module('Integration | Component | application/detail-header', function (hooks) { assert.dom('[data-test-button="nudge-button"]').hasAttribute('disabled'); }); + + test('it disables nudge button based on 24h timeout', async function (assert) { + const now = Date.now(); + const recentNudge = new Date(now - 12 * 60 * 60 * 1000).toISOString(); + + this.set('application', { + status: 'pending', + lastNudgedAt: recentNudge, + }); + + await render( + hbs``, + ); + assert.dom('[data-test-button="nudge-button"]').hasAttribute('disabled'); + }); }); diff --git a/tests/integration/components/application/feedback-card-test.js b/tests/integration/components/application/feedback-card-test.js index 51d17688..48ca763b 100644 --- a/tests/integration/components/application/feedback-card-test.js +++ b/tests/integration/components/application/feedback-card-test.js @@ -42,4 +42,17 @@ module('Integration | Component | application/feedback-card', function (hooks) { assert.dom('[data-test-feedback-date]').hasText('N/A'); }); + + test('it handles invalid date string correctly', async function (assert) { + await render(hbs` + + `); + + assert.dom('[data-test-feedback-date]').hasText('N/A'); + }); }); diff --git a/tests/integration/components/application/info-card-test.js b/tests/integration/components/application/info-card-test.js index 4a06180a..089303da 100644 --- a/tests/integration/components/application/info-card-test.js +++ b/tests/integration/components/application/info-card-test.js @@ -17,30 +17,32 @@ module('Integration | Component | application/info-card', function (hooks) { ); assert.dom('[data-test-info-card-title]').hasText('About'); - assert.dom('[data-test-info-item]').doesNotExist(); - assert.dom('[data-test-info-block]').exists({ count: 2 }); + assert.dom('[data-test-info-section]').exists({ count: 2 }); assert.dom('.info-label').includesText('Intro'); assert.dom('.info-value').includesText('Value 1'); + + assert + .dom('[data-test-info-section]:nth-child(1) .info-label') + .hasText('Intro'); + assert + .dom('[data-test-info-section]:nth-child(1) .info-value') + .hasText('Value 1'); + assert + .dom('[data-test-info-section]:nth-child(2) .info-label') + .hasText('Fact'); + assert + .dom('[data-test-info-section]:nth-child(2) .info-value') + .hasText('Value 2'); }); - test('it renders grid sections correctly', async function (assert) { - this.set('sections', [ - { - type: 'grid', - items: [ - { label: 'Item 1', value: 'Value 1' }, - { label: 'Item 2', value: 'Value 2' }, - ], - }, - ]); + test('it handles empty sections correctly', async function (assert) { + this.set('sections', []); await render( - hbs``, + hbs``, ); - assert.dom('[data-test-info-section]').exists(); - assert.dom('[data-test-info-item]').exists({ count: 2 }); - assert.dom('.info-label').includesText('Item 1'); - assert.dom('.info-value').includesText('Value 1'); + assert.dom('[data-test-info-card-title]').hasText('Empty'); + assert.dom('[data-test-info-section]').doesNotExist(); }); }); diff --git a/tests/integration/components/application/social-link-pill-test.js b/tests/integration/components/application/social-link-pill-test.js index 4c754f95..ea059cbe 100644 --- a/tests/integration/components/application/social-link-pill-test.js +++ b/tests/integration/components/application/social-link-pill-test.js @@ -22,5 +22,30 @@ module( assert.dom('[data-test-social-link]').includesText('GitHub'); assert.dom('[data-test-platform="GitHub"]').exists(); }); + + test('it renders LinkedIn and other platforms correctly', async function (assert) { + this.set('platform', 'LinkedIn'); + this.set('userName', 'testuser'); + + await render( + hbs``, + ); + + assert + .dom('[data-test-social-link]') + .hasAttribute('href', 'https://linkedin.com/in/testuser'); + assert.dom('[data-test-social-link]').includesText('LinkedIn'); + }); + + test('it handles unknown platforms with fallback icon', async function (assert) { + this.set('platform', 'unknown'); + this.set('userName', 'user'); + + await render( + hbs``, + ); + assert.dom('[data-test-social-link]').exists(); + assert.dom('[data-test-social-link]').includesText('unknown'); + }); }, ); From 9853db0d5b88a658dafc6490f990168716735042 Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Tue, 20 Jan 2026 02:03:28 +0530 Subject: [PATCH 4/4] refactor: use constants for applications data --- .../application/detail-header-test.js | 22 ++++++++++++++----- .../application/feedback-card-test.js | 21 +++++++++--------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/tests/integration/components/application/detail-header-test.js b/tests/integration/components/application/detail-header-test.js index 1d3b732c..e1e3c771 100644 --- a/tests/integration/components/application/detail-header-test.js +++ b/tests/integration/components/application/detail-header-test.js @@ -8,7 +8,8 @@ module('Integration | Component | application/detail-header', function (hooks) { setupRenderingTest(hooks); test('it renders application details correctly', async function (assert) { - this.set('application', APPLICATIONS_DATA); + const user = APPLICATIONS_DATA; + this.set('application', user); this.set('isAdmin', false); await render(hbs` @@ -18,10 +19,18 @@ module('Integration | Component | application/detail-header', function (hooks) { /> `); - assert.dom('[data-test-user-name]').includesText('John Doe'); - assert.dom('[data-test-status-badge]').hasText('ACCEPTED'); - assert.dom('[data-test-score-value]').hasText('250'); - assert.dom('[data-test-social-link]').exists({ count: 7 }); + const { firstName, lastName } = user.biodata; + assert + .dom('[data-test-user-name]') + .includesText(`${firstName} ${lastName}`); + assert.dom('[data-test-status-badge]').hasText(user.status.toUpperCase()); + assert.dom('[data-test-score-value]').hasText(String(user.score)); + assert + .dom('[data-test-nudge-details]') + .includesText(String(user.nudgeCount)); + assert + .dom('[data-test-social-link]') + .exists({ count: Object.keys(user.socialLink).length }); assert.dom('[data-test-button="nudge-button"]').exists(); assert.dom('[data-test-button="edit-button"]').exists(); @@ -29,7 +38,8 @@ module('Integration | Component | application/detail-header', function (hooks) { }); test('it renders admin actions correctly', async function (assert) { - this.set('application', APPLICATIONS_DATA); + const user = APPLICATIONS_DATA; + this.set('application', user); this.set('isAdmin', true); await render(hbs` diff --git a/tests/integration/components/application/feedback-card-test.js b/tests/integration/components/application/feedback-card-test.js index 48ca763b..b3571b45 100644 --- a/tests/integration/components/application/feedback-card-test.js +++ b/tests/integration/components/application/feedback-card-test.js @@ -2,17 +2,14 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'website-www/tests/helpers'; import { render } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; +import { APPLICATIONS_DATA } from 'website-www/tests/constants/application-data'; module('Integration | Component | application/feedback-card', function (hooks) { setupRenderingTest(hooks); test('it renders feedback details correctly', async function (assert) { - this.set('feedback', { - status: 'accepted', - feedback: 'Great job!', - reviewerName: 'Ankush', - createdAt: '2026-01-14T15:37:10.991Z', - }); + const feedback = APPLICATIONS_DATA.feedback[0]; + this.set('feedback', feedback); await render(hbs` `); - assert.dom('[data-test-status-badge]').hasText('ACCEPTED'); - assert.dom('[data-test-feedback-text]').hasText('Great job!'); - assert.dom('[data-test-feedback-reviewer]').includesText('Ankush'); + assert + .dom('[data-test-status-badge]') + .hasText(feedback.status.toUpperCase()); + assert.dom('[data-test-feedback-text]').hasText(feedback.feedback); + assert + .dom('[data-test-feedback-reviewer]') + .includesText(feedback.reviewerName); assert .dom('[data-test-feedback-date]') - .hasText(new Date('2026-01-14T15:37:10.991Z').toLocaleDateString()); + .hasText(new Date(feedback.createdAt).toLocaleDateString()); }); test('it renders N/A for missing date', async function (assert) {