-
-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: Refactored the build table interactor
- Loading branch information
1 parent
5e4757d
commit 0f373bb
Showing
16 changed files
with
579 additions
and
342 deletions.
There are no files selected for viewing
19 changes: 10 additions & 9 deletions
19
src/interactors/buildTable/__tests__/calculateBests.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,21 @@ | ||
const stats = require('../../__tests__/mocks/stats.json'); | ||
const { entries } = require('../../../../tests/mocks'); | ||
const calculateBests = require('../calculateBests'); | ||
|
||
describe('Interactors | .buildTable | .calculateBests', () => { | ||
it('returns the best stats for MAX optimization', () => { | ||
const response = calculateBests(stats); | ||
it('returns the best stats for DESC sort order', () => { | ||
const response = calculateBests(entries); | ||
expect(response).toMatchObject({ | ||
totalReviews: 37, | ||
totalComments: 99, | ||
commentsPerReview: 3, | ||
totalReviews: 4, | ||
totalComments: 5, | ||
commentsPerReview: 5, | ||
openedPullRequests: 30, | ||
}); | ||
}); | ||
|
||
it('returns the best stats for MIN optimization', () => { | ||
const response = calculateBests(stats); | ||
it('returns the best stats for ASC sort order', () => { | ||
const response = calculateBests(entries); | ||
expect(response).toMatchObject({ | ||
timeToReview: 25000, | ||
timeToReview: 1_000_000, | ||
}); | ||
}); | ||
}); |
218 changes: 115 additions & 103 deletions
218
src/interactors/buildTable/__tests__/getTableData.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,127 +1,139 @@ | ||
const { t } = require('../../../i18n'); | ||
const reviewers = require('../../__tests__/mocks/populatedReviewers.json'); | ||
const { entries } = require('../../../../tests/mocks'); | ||
const { STATS, VALID_STATS } = require('../../../config/stats'); | ||
Check failure on line 3 in src/interactors/buildTable/__tests__/getTableData.test.js GitHub Actions / lint
|
||
const getTableData = require('../getTableData'); | ||
|
||
const bests = { | ||
totalReviews: 4, | ||
totalComments: 5, | ||
commentsPerReview: 5, | ||
timeToReview: 2052500, | ||
openedPullRequests: 30, | ||
timeToReview: 1_000_000, | ||
}; | ||
|
||
const TITLES = { | ||
avatar: t('table.columns.avatar'), | ||
username: t('table.columns.username'), | ||
timeToReview: t('table.columns.timeToReview'), | ||
totalReviews: t('table.columns.totalReviews'), | ||
totalComments: t('table.columns.totalComments'), | ||
}; | ||
describe('Interactors | .buildTable | .getTableData', () => { | ||
const defaultParams = { | ||
bests, | ||
entries, | ||
mainStats: VALID_STATS, | ||
disableLinks: true, | ||
displayCharts: false, | ||
}; | ||
|
||
const AVATAR1 = '<a href="https://github.com/user1"><img src="https://avatars.githubusercontent.com/u/1234" width="20"></a>'; | ||
const AVATAR2 = '<a href="https://github.com/user2"><img src="https://avatars.githubusercontent.com/u/5678" width="20"></a>'; | ||
const AVATAR1_BIG = '<a href="https://github.com/user1"><img src="https://avatars.githubusercontent.com/u/1234" width="32"></a>'; | ||
const AVATAR2_BIG = '<a href="https://github.com/user2"><img src="https://avatars.githubusercontent.com/u/5678" width="32"></a>'; | ||
|
||
const SIMPLE_RESPONSE = [ | ||
TITLES, | ||
{ | ||
avatar: AVATAR1, | ||
username: 'user1', | ||
timeToReview: '[34m](https://app.flowwer.dev/charts/review-time/1)', | ||
totalReviews: '4', | ||
totalComments: '1', | ||
}, | ||
{ | ||
avatar: AVATAR2, | ||
username: 'user2', | ||
timeToReview: '[2h 21m](https://app.flowwer.dev/charts/review-time/2)', | ||
totalReviews: '1', | ||
totalComments: '5', | ||
}, | ||
]; | ||
|
||
const CHARTS_RESPONSE = [ | ||
TITLES, | ||
{ | ||
avatar: AVATAR1_BIG, | ||
username: 'user1<br/>🥇', | ||
timeToReview: '[**34m**](https://app.flowwer.dev/charts/review-time/1)<br/>▀▀', | ||
totalReviews: '**4**<br/>▀▀▀▀▀▀▀▀', | ||
totalComments: '1<br/>▀▀', | ||
}, | ||
{ | ||
avatar: AVATAR2_BIG, | ||
username: 'user2<br/>🥈', | ||
timeToReview: '[2h 21m](https://app.flowwer.dev/charts/review-time/2)<br/>▀▀▀▀▀▀▀▀', | ||
totalReviews: '1<br/>▀▀', | ||
totalComments: '**5**<br/>▀▀▀▀▀▀▀▀', | ||
}, | ||
]; | ||
|
||
const NO_LINKS_RESPONSE = [ | ||
TITLES, | ||
{ | ||
avatar: AVATAR1, | ||
username: 'user1', | ||
timeToReview: '34m', | ||
totalReviews: '4', | ||
totalComments: '1', | ||
}, | ||
{ | ||
avatar: AVATAR2, | ||
username: 'user2', | ||
timeToReview: '2h 21m', | ||
totalReviews: '1', | ||
totalComments: '5', | ||
}, | ||
]; | ||
|
||
const CHARTS_NO_LINKS_RESPONSE = [ | ||
TITLES, | ||
{ | ||
avatar: AVATAR1_BIG, | ||
username: 'user1<br/>🥇', | ||
timeToReview: '**34m**<br/>▀▀', | ||
totalReviews: '**4**<br/>▀▀▀▀▀▀▀▀', | ||
totalComments: '1<br/>▀▀', | ||
}, | ||
{ | ||
avatar: AVATAR2_BIG, | ||
username: 'user2<br/>🥈', | ||
timeToReview: '2h 21m<br/>▀▀▀▀▀▀▀▀', | ||
totalReviews: '1<br/>▀▀', | ||
totalComments: '**5**<br/>▀▀▀▀▀▀▀▀', | ||
}, | ||
]; | ||
it('builds the headers successfully', () => { | ||
const response = getTableData(defaultParams); | ||
expect(response.headers[0]).toEqual({ text: t('table.columns.username') }); | ||
VALID_STATS.forEach((statName, index) => { | ||
expect(response.headers[index + 1]).toEqual({ text: t(`table.columns.${statName}`) }); | ||
}); | ||
}); | ||
|
||
describe('Interactors | .buildTable | .getTableData', () => { | ||
describe('when sending reviewers only', () => { | ||
it('returns the default case data', () => { | ||
const response = getTableData({ reviewers }); | ||
expect(response).toEqual(SIMPLE_RESPONSE); | ||
it('builds the users correctly', () => { | ||
const response = getTableData(defaultParams); | ||
response.rows.forEach((row, index) => { | ||
expect(row.user).toEqual({ | ||
link: entries[index].user.url, | ||
image: entries[index].user.avatarUrl, | ||
text: entries[index].user.login, | ||
emoji: null, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('when sending bests and display charts', () => { | ||
it('returns the data with charts and medals', () => { | ||
const response = getTableData({ bests, reviewers, displayCharts: true }); | ||
expect(response).toEqual(CHARTS_RESPONSE); | ||
it('builds the stats successfully', () => { | ||
const response = getTableData(defaultParams); | ||
response.rows.forEach((row) => { | ||
row.stats.forEach((stat) => { | ||
expect(stat).toEqual({ | ||
text: expect.any(String), | ||
bold: expect.any(Boolean), | ||
link: null, | ||
chartValue: null, | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('when disabling links', () => { | ||
it('returns the data without external links', () => { | ||
const response = getTableData({ reviewers, disableLinks: true }); | ||
expect(response).toEqual(NO_LINKS_RESPONSE); | ||
it('displays only the requested stats', () => { | ||
const testCases = [ | ||
VALID_STATS, | ||
[VALID_STATS[0]], | ||
[VALID_STATS[VALID_STATS.length - 1], VALID_STATS[0]], | ||
]; | ||
|
||
testCases.forEach((mainStats) => { | ||
const response = getTableData({ ...defaultParams, mainStats }); | ||
expect(response.headers.length).toEqual(mainStats.length + 1); | ||
response.rows.forEach((row) => { | ||
expect(row.stats.length).toEqual(mainStats.length); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('when disabling links but adding charts', () => { | ||
it('returns the data without external links', () => { | ||
const response = getTableData({ | ||
bests, reviewers, displayCharts: true, disableLinks: true, | ||
it('adds the stats link when required', () => { | ||
const response = getTableData({ | ||
...defaultParams, | ||
disableLinks: false, | ||
}); | ||
|
||
response.rows.forEach((row, index) => { | ||
VALID_STATS.forEach((statName, statIndex) => { | ||
const link = entries[index].urls[statName] || null; | ||
expect(row.stats[statIndex].link).toEqual(link); | ||
}); | ||
expect(response).toEqual(CHARTS_NO_LINKS_RESPONSE); | ||
}); | ||
}); | ||
|
||
it('adds the bold option to the best stats', () => { | ||
const mainStats = [STATS.totalReviews.id]; | ||
const response = getTableData({ | ||
...defaultParams, | ||
mainStats, | ||
}); | ||
|
||
expect(response.rows[0].stats[0].bold).toEqual(true); | ||
expect(response.rows[1].stats[0].bold).toEqual(false); | ||
expect(response.rows[2].stats[0].bold).toEqual(false); | ||
}); | ||
|
||
it('adds the chart value when required', () => { | ||
const mainStats = [STATS.totalReviews.id]; | ||
const response = getTableData({ | ||
...defaultParams, | ||
mainStats, | ||
displayCharts: true, | ||
}); | ||
|
||
response.rows.forEach((row, index) => { | ||
mainStats.forEach((statName, statIndex) => { | ||
const chartValue = entries[index].contributions[statName]; | ||
expect(row.stats[statIndex].chartValue).toEqual(chartValue); | ||
}); | ||
}); | ||
}); | ||
|
||
it('adds the emoji when required', () => { | ||
const displayCharts = true; | ||
const response = getTableData({ | ||
...defaultParams, | ||
displayCharts, | ||
}); | ||
|
||
expect(response.rows[0].user.emoji).toEqual('medal1'); | ||
expect(response.rows[1].user.emoji).toEqual('medal2'); | ||
expect(response.rows[2].user.emoji).toEqual('medal3'); | ||
}); | ||
|
||
it('parses the stat text correctly', () => { | ||
const mainStats = [STATS.timeToReview.id]; | ||
const response = getTableData({ | ||
...defaultParams, | ||
mainStats, | ||
}); | ||
response.rows.forEach((row, index) => { | ||
const value = entries[index].stats.timeToReview; | ||
const text = STATS.timeToReview.parser(value); | ||
expect(row.stats[0].text).toEqual(text); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,50 @@ | ||
const reviewers = require('../../__tests__/mocks/populatedReviewers.json'); | ||
const { entries } = require('../../../../tests/mocks'); | ||
const { VALID_STATS } = require('../../../config/stats'); | ||
Check failure on line 2 in src/interactors/buildTable/__tests__/index.test.js GitHub Actions / lint
|
||
const getTableData = require('../getTableData'); | ||
const buildTable = require('../index'); | ||
|
||
const SIMPLE_RESPONSE = `| | User | Total reviews | Time to review | Total comments | | ||
| ---------------------------------------------------------------------------------------------------------- | ----- | ------------- | -------------- | -------------- | | ||
| <a href="https://github.com/user1"><img src="https://avatars.githubusercontent.com/u/1234" width="20"></a> | user1 | **4** | **34m** | 1 | | ||
| <a href="https://github.com/user2"><img src="https://avatars.githubusercontent.com/u/5678" width="20"></a> | user2 | 1 | 2h 21m | **5** |`; | ||
|
||
const CHARTS_RESPONSE = `| | User | Total reviews | Time to review | Total comments | | ||
| ---------------------------------------------------------------------------------------------------------- | ------------ | ------------------ | ------------------- | ------------------ | | ||
| <a href="https://github.com/user1"><img src="https://avatars.githubusercontent.com/u/1234" width="32"></a> | user1<br/>🥇 | **4**<br/>▀▀▀▀▀▀▀▀ | **34m**<br/>▀▀ | 1<br/>▀▀ | | ||
| <a href="https://github.com/user2"><img src="https://avatars.githubusercontent.com/u/5678" width="32"></a> | user2<br/>🥈 | 1<br/>▀▀ | 2h 21m<br/>▀▀▀▀▀▀▀▀ | **5**<br/>▀▀▀▀▀▀▀▀ |`; | ||
|
||
const LINKS_RESPONSE = `| | User | Total reviews | Time to review | Total comments | | ||
| ---------------------------------------------------------------------------------------------------------- | ----- | ------------- | ------------------------------------------------------- | -------------- | | ||
| <a href="https://github.com/user1"><img src="https://avatars.githubusercontent.com/u/1234" width="20"></a> | user1 | **4** | [**34m**](https://app.flowwer.dev/charts/review-time/1) | 1 | | ||
| <a href="https://github.com/user2"><img src="https://avatars.githubusercontent.com/u/5678" width="20"></a> | user2 | 1 | [2h 21m](https://app.flowwer.dev/charts/review-time/2) | **5** |`; | ||
|
||
const LINKS_AND_CHARTS_RESPONSE = `| | User | Total reviews | Time to review | Total comments | | ||
| ---------------------------------------------------------------------------------------------------------- | ------------ | ------------------ | ------------------------------------------------------------------- | ------------------ | | ||
| <a href="https://github.com/user1"><img src="https://avatars.githubusercontent.com/u/1234" width="32"></a> | user1<br/>🥇 | **4**<br/>▀▀▀▀▀▀▀▀ | [**34m**](https://app.flowwer.dev/charts/review-time/1)<br/>▀▀ | 1<br/>▀▀ | | ||
| <a href="https://github.com/user2"><img src="https://avatars.githubusercontent.com/u/5678" width="32"></a> | user2<br/>🥈 | 1<br/>▀▀ | [2h 21m](https://app.flowwer.dev/charts/review-time/2)<br/>▀▀▀▀▀▀▀▀ | **5**<br/>▀▀▀▀▀▀▀▀ |`; | ||
jest.mock('../getTableData', () => jest.fn()); | ||
|
||
describe('Interactors | .buildTable', () => { | ||
it('returns all available reviewers in a set of pull requests', () => { | ||
const response = buildTable({ reviewers, disableLinks: true }); | ||
expect(response).toEqual(SIMPLE_RESPONSE); | ||
const defaultParams = { | ||
entries, | ||
limit: null, | ||
sortKey: VALID_STATS[0], | ||
mainStats: VALID_STATS, | ||
disableLinks: true, | ||
displayCharts: false, | ||
}; | ||
|
||
getTableData.mockImplementation(jest.requireActual('../getTableData')); | ||
|
||
beforeEach(() => { | ||
getTableData.mockClear(); | ||
}); | ||
|
||
it('can add charts to the table', () => { | ||
const response = buildTable({ reviewers, displayCharts: true, disableLinks: true }); | ||
expect(response).toEqual(CHARTS_RESPONSE); | ||
it('limits the results', () => { | ||
const response1 = buildTable(defaultParams); | ||
expect(response1.rows.length).toEqual(entries.length); | ||
|
||
const limit = 1; | ||
const response2 = buildTable({ ...defaultParams, limit }); | ||
expect(response2.rows.length).toEqual(limit); | ||
}); | ||
|
||
it('with links enabled by default', () => { | ||
const response = buildTable({ reviewers }); | ||
expect(response).toEqual(LINKS_RESPONSE); | ||
it('sorts data by the given key', () => { | ||
const response = buildTable(defaultParams); | ||
expect(response.rows[0].user.text).toEqual('user1'); | ||
expect(response.rows[1].user.text).toEqual('user2'); | ||
expect(response.rows[2].user.text).toEqual('user3'); | ||
}); | ||
|
||
it('with links and charts', () => { | ||
const response = buildTable({ reviewers, displayCharts: true }); | ||
expect(response).toEqual(LINKS_AND_CHARTS_RESPONSE); | ||
it('calls build table data with the correct params', () => { | ||
buildTable(defaultParams); | ||
expect(getTableData).toHaveBeenCalledWith(expect.objectContaining({ | ||
entries, | ||
bests: expect.any(Object), | ||
mainStats: defaultParams.mainStats, | ||
disableLinks: defaultParams.disableLinks, | ||
displayCharts: defaultParams.displayCharts, | ||
})); | ||
}); | ||
}); |
Oops, something went wrong.