diff --git a/src/app/domain/entityStore/entities/UserSettingsEntity.ts b/src/app/domain/entityStore/entities/UserSettingsEntity.ts index d687912..598ea6f 100644 --- a/src/app/domain/entityStore/entities/UserSettingsEntity.ts +++ b/src/app/domain/entityStore/entities/UserSettingsEntity.ts @@ -1,37 +1,10 @@ -import { entityFromPkOnlyEntity } from '@symphoniacloud/dynamodb-entity-store' +import { entityFromPkOnlyEntity, typePredicateParser } from '@symphoniacloud/dynamodb-entity-store' import { USER_SETTINGS } from '../entityTypes' -import { PersistedUserSettings } from '../../types/UserSettings' -import { DynamoDBValues } from '@symphoniacloud/dynamodb-entity-store/dist/cjs/entities' -import { parseDynamoDBDictToMap } from '../entityStoreEntitySupport' -import { identity } from '../../../util/functional' - -export function parseUserSettings(item: DynamoDBValues): PersistedUserSettings { - // TODO - check things actually exist - return { - userId: item.userId, - github: { - accounts: parseDynamoDBDictToMap( - Number.parseInt, - (value) => ({ - ...value, - repos: parseDynamoDBDictToMap( - Number.parseInt, - (value) => ({ - ...value, - workflows: parseDynamoDBDictToMap(Number.parseInt, identity, value.workflows ?? {}) - }), - value.repos ?? {} - ) - }), - item.github.accounts - ) - } - } -} +import { isUserSettings, PersistedUserSettings } from '../../types/UserSettings' export const UserSettingsEntity = entityFromPkOnlyEntity({ type: USER_SETTINGS, - parse: parseUserSettings, + parse: typePredicateParser(isUserSettings, USER_SETTINGS), pk(source: Pick) { return `USERID#${source.userId}` } diff --git a/src/app/domain/types/UserSettings.ts b/src/app/domain/types/UserSettings.ts index bfc0601..6865d0b 100644 --- a/src/app/domain/types/UserSettings.ts +++ b/src/app/domain/types/UserSettings.ts @@ -1,4 +1,4 @@ -import { GithubAccountId, GithubRepoId, GithubUserId, GithubWorkflowId, isGithubUserId } from './GithubKeys' +import { GithubUserId, isGithubUserId } from './GithubKeys' import { isNotNullObject } from '../../util/types' export type UserSetting = 'visible' | 'notify' @@ -19,10 +19,16 @@ export function isUserSettings(x: unknown): x is PersistedUserSettings { ) } +// Various types here use a string for Record key, rather than GithubAccountID, etc. +// That's because JavaScript always uses strings for object keys, even if the Record type says number +// An earlier version of this code used Maps to keep the strong typing of the ID keys +// but it made the code more verbose - especially for tests - so I decided just to suck it up +// and go with string ID keys + export interface PersistedUserSettings { userId: GithubUserId github: { - accounts: Map + accounts: Record } } @@ -32,11 +38,11 @@ export interface PersistedVisibleAndNotifyConfigurable { } export interface PersistedGithubAccountSettings extends PersistedVisibleAndNotifyConfigurable { - repos: Map + repos: Record } export interface PersistedGithubRepoSettings extends PersistedVisibleAndNotifyConfigurable { - workflows: Map + workflows: Record } export type PersistedGithubWorkflowSettings = PersistedVisibleAndNotifyConfigurable @@ -46,18 +52,18 @@ export type PersistedGithubWorkflowSettings = PersistedVisibleAndNotifyConfigura export interface CalculatedUserSettings { userId: GithubUserId github: { - accounts: Map + accounts: Record } } export type CalculatedVisibleAndNotifyConfigurable = Required export interface CalculatedGithubAccountSettings extends CalculatedVisibleAndNotifyConfigurable { - repos: Map + repos: Record } export interface CalculatedGithubRepoSettings extends CalculatedVisibleAndNotifyConfigurable { - workflows: Map + workflows: Record } export type CalculatedGithubWorkflowSettings = CalculatedVisibleAndNotifyConfigurable @@ -65,8 +71,9 @@ export type CalculatedGithubWorkflowSettings = CalculatedVisibleAndNotifyConfigu // *** export interface DisplayableUserSettings { + userId: GithubUserId github: { - accounts: Map + accounts: Record } } @@ -77,11 +84,11 @@ export interface Displayable { export interface DisplayableGithubAccountSettings extends CalculatedVisibleAndNotifyConfigurable, Displayable { - repos: Map + repos: Record } export interface DisplayableGithubRepoSettings extends CalculatedVisibleAndNotifyConfigurable, Displayable { - workflows: Map + workflows: Record } export type DisplayableGithubWorkflowSettings = CalculatedGithubWorkflowSettings & Displayable diff --git a/src/app/domain/user/calculatedUserSettings.ts b/src/app/domain/user/calculatedUserSettings.ts index d2bc013..fc9f73f 100644 --- a/src/app/domain/user/calculatedUserSettings.ts +++ b/src/app/domain/user/calculatedUserSettings.ts @@ -1,7 +1,6 @@ import { CalculatedGithubAccountSettings, CalculatedGithubRepoSettings, - CalculatedGithubWorkflowSettings, CalculatedUserSettings, CalculatedVisibleAndNotifyConfigurable, PersistedGithubAccountSettings, @@ -10,7 +9,7 @@ import { PersistedVisibleAndNotifyConfigurable } from '../types/UserSettings' import { GithubWorkflow } from '../types/GithubWorkflow' -import { GithubAccountId, GithubRepoId, GithubRepoKey, GithubWorkflowId } from '../types/GithubKeys' +import { GithubAccountId, GithubRepoKey } from '../types/GithubKeys' import { findUniqueAccountIds, findUniqueRepoIdsForAccount, @@ -23,16 +22,14 @@ export function calculateUserSettings( settings: PersistedUserSettings, allWorkflows: GithubWorkflow[] ): CalculatedUserSettings { - const accountEntries: [GithubAccountId, CalculatedGithubAccountSettings][] = findUniqueAccountIds( - allWorkflows - ).map((id) => { - return [id, calculateAccountSettings(settings.github.accounts.get(id), id, allWorkflows)] - }) - return { userId: settings.userId, github: { - accounts: new Map(accountEntries) + accounts: Object.fromEntries( + findUniqueAccountIds(allWorkflows).map((id) => { + return [id, calculateAccountSettings(settings.github.accounts[id], id, allWorkflows)] + }) + ) } } } @@ -43,27 +40,23 @@ export function calculateAccountSettings( allWorkflows: GithubWorkflow[] ): CalculatedGithubAccountSettings { const visibleAndNotify = calculateVisibleAndNotifyConfigurable(settings, DEFAULT_ACCOUNT_NOTIFY) + const repos = visibleAndNotify.visible + ? Object.fromEntries( + findUniqueRepoIdsForAccount(allWorkflows, accountId).map((repoId) => { + return [ + repoId, + calculateRepoSettings( + settings?.repos[repoId], + { ownerId: accountId, repoId }, + allWorkflows, + visibleAndNotify.notify + ) + ] + }) + ) + : {} - if (!visibleAndNotify.visible) { - return { ...visibleAndNotify, repos: new Map() } - } - - return { - ...visibleAndNotify, - repos: new Map( - findUniqueRepoIdsForAccount(allWorkflows, accountId).map((repoId) => { - return [ - repoId, - calculateRepoSettings( - settings?.repos.get(repoId), - { ownerId: accountId, repoId }, - allWorkflows, - visibleAndNotify.notify - ) - ] - }) - ) - } + return { ...visibleAndNotify, repos } } export function calculateRepoSettings( @@ -73,22 +66,18 @@ export function calculateRepoSettings( defaultNotify: boolean ): CalculatedGithubRepoSettings { const visibleAndNotify = calculateVisibleAndNotifyConfigurable(repoSettings, defaultNotify) + const workflows = visibleAndNotify.visible + ? Object.fromEntries( + findWorkflowsForRepo(allWorkflows, repoKey).map((wf) => { + return [ + wf.workflowId, + calculateWorkflowSettings(repoSettings?.workflows[wf.workflowId], visibleAndNotify.notify) + ] + }) + ) + : {} - if (!visibleAndNotify.visible) { - return { ...visibleAndNotify, workflows: new Map() } - } - - return { - ...visibleAndNotify, - workflows: new Map( - findWorkflowsForRepo(allWorkflows, repoKey).map((wf) => { - return [ - wf.workflowId, - calculateWorkflowSettings(repoSettings?.workflows.get(wf.workflowId), visibleAndNotify.notify) - ] - }) - ) - } + return { ...visibleAndNotify, workflows } } export const calculateWorkflowSettings = calculateVisibleAndNotifyConfigurable diff --git a/src/app/domain/user/displayableUserSettings.ts b/src/app/domain/user/displayableUserSettings.ts index 41e725c..54cad9b 100644 --- a/src/app/domain/user/displayableUserSettings.ts +++ b/src/app/domain/user/displayableUserSettings.ts @@ -10,13 +10,7 @@ import { PersistedUserSettings } from '../types/UserSettings' import { GithubWorkflow } from '../types/GithubWorkflow' -import { - GithubAccountId, - GithubRepoId, - GithubRepoKey, - GithubWorkflowId, - GithubWorkflowKey -} from '../types/GithubKeys' +import { GithubAccountId, GithubRepoKey, GithubWorkflowKey } from '../types/GithubKeys' import { findAccountName, findRepoName, findWorkflowName } from '../github/githubWorkflow' import { calculateUserSettings } from './calculatedUserSettings' @@ -32,11 +26,12 @@ function toDisplayableUserSettings( workflows: GithubWorkflow[] ): DisplayableUserSettings { return { + userId: userSettings.userId, github: { - accounts: new Map( - Array.from(userSettings.github.accounts.entries()).map(([accountId, accountSettings]) => [ + accounts: Object.fromEntries( + Object.entries(userSettings.github.accounts).map(([accountId, accountSettings]) => [ accountId, - toDisplayableAccountSettings(accountId, accountSettings, workflows) + toDisplayableAccountSettings(Number(accountId), accountSettings, workflows) ]) ) } @@ -51,13 +46,13 @@ export function toDisplayableAccountSettings( return { ...accountSettings, name: findAccountName(allWorkflows, accountId), - repos: new Map( - Array.from(accountSettings.repos.entries()).map(([repoId, repoSettings]) => [ + repos: Object.fromEntries( + Object.entries(accountSettings.repos).map(([repoId, repoSettings]) => [ repoId, toDisplayableRepoSettings( { ownerId: accountId, - repoId + repoId: Number(repoId) }, repoSettings, allWorkflows @@ -75,10 +70,14 @@ export function toDisplayableRepoSettings( return { ...repoSettings, name: findRepoName(allWorkflows, repoKey), - workflows: new Map( - Array.from(repoSettings.workflows.entries()).map(([workflowId, workflowSettings]) => [ + workflows: Object.fromEntries( + Object.entries(repoSettings.workflows).map(([workflowId, workflowSettings]) => [ workflowId, - toDisplayableWorkflowSettings({ ...repoKey, workflowId }, workflowSettings, allWorkflows) + toDisplayableWorkflowSettings( + { ...repoKey, workflowId: Number(workflowId) }, + workflowSettings, + allWorkflows + ) ]) ) } diff --git a/src/app/domain/user/persistedUserSettings.ts b/src/app/domain/user/persistedUserSettings.ts index 0e6f965..1b3a70c 100644 --- a/src/app/domain/user/persistedUserSettings.ts +++ b/src/app/domain/user/persistedUserSettings.ts @@ -6,16 +6,9 @@ import { PersistedUserSettings, UserSetting } from '../types/UserSettings' -import { - GithubAccountId, - GithubRepoId, - GithubRepoKey, - GithubUserId, - GithubWorkflowId, - GithubWorkflowKey -} from '../types/GithubKeys' +import { GithubAccountId, GithubRepoKey, GithubUserId, GithubWorkflowKey } from '../types/GithubKeys' import { UserSettingsEntity } from '../entityStore/entities/UserSettingsEntity' -import { getFromMapOrSetNewAndReturn } from '../../util/collections' +import { getOrSetNewAndReturn } from '../../util/collections' function userSettingsEntity(appState: AppState) { return appState.entityStore.for(UserSettingsEntity) @@ -46,7 +39,7 @@ function initialUserSettings(userId: GithubUserId): PersistedUserSettings { return { userId, github: { - accounts: new Map() + accounts: {} } } } @@ -117,8 +110,8 @@ function getOrCreateAndReturnAccountSettings( settings: PersistedUserSettings, accountId: GithubAccountId ): PersistedGithubAccountSettings { - return getFromMapOrSetNewAndReturn(settings.github.accounts, accountId, () => ({ - repos: new Map() + return getOrSetNewAndReturn(settings.github.accounts, `${accountId}`, () => ({ + repos: {} })) } @@ -127,8 +120,8 @@ function getOrCreateAndReturnRepoSettings( repoKey: GithubRepoKey ): PersistedGithubRepoSettings { const accountSettings = getOrCreateAndReturnAccountSettings(settings, repoKey.ownerId) - return getFromMapOrSetNewAndReturn(accountSettings.repos, repoKey.repoId, () => ({ - workflows: new Map() + return getOrSetNewAndReturn(accountSettings.repos, `${repoKey.repoId}`, () => ({ + workflows: {} })) } @@ -137,5 +130,5 @@ function getOrCreateAndReturnWorkflowSettings( workflowKey: GithubWorkflowKey ): PersistedGithubWorkflowSettings { const repoSettings = getOrCreateAndReturnRepoSettings(settings, workflowKey) - return getFromMapOrSetNewAndReturn(repoSettings.workflows, workflowKey.workflowId, () => ({})) + return getOrSetNewAndReturn(repoSettings.workflows, `${workflowKey.workflowId}`, () => ({})) } diff --git a/src/app/domain/user/userNotifyable.ts b/src/app/domain/user/userNotifyable.ts index 735cdad..0161d23 100644 --- a/src/app/domain/user/userNotifyable.ts +++ b/src/app/domain/user/userNotifyable.ts @@ -28,10 +28,9 @@ export async function getWorkflowNotifyEnabledForUser( await getUserSettings(appState, userId), await getWorkflowsForUser(appState, userId) ) - const yesNotify = userSettings.github.accounts - .get(workflow.ownerId) - ?.repos.get(workflow.repoId) - ?.workflows.get(workflow.workflowId)?.notify + const yesNotify = + userSettings.github.accounts[workflow.ownerId]?.repos[workflow.repoId]?.workflows[workflow.workflowId] + .notify if (yesNotify === undefined) { logger.warn(`No calculated user notify setting for workflow`, { workflow, userSettings }) return false diff --git a/src/app/domain/user/userVisible.ts b/src/app/domain/user/userVisible.ts index d7e4184..04f8925 100644 --- a/src/app/domain/user/userVisible.ts +++ b/src/app/domain/user/userVisible.ts @@ -94,8 +94,7 @@ export async function getRecentActiveBranchesForUser(appState: AppState, userId: function toVisibleEvents(allEvents: GithubWorkflowRunEvent[], userSettings: CalculatedUserSettings) { const visibleEvents = allEvents.filter( ({ ownerId, repoId, workflowId }) => - userSettings.github.accounts.get(ownerId)?.repos.get(repoId)?.workflows.get(workflowId)?.visible ?? - false + userSettings.github.accounts[ownerId]?.repos[repoId]?.workflows[workflowId]?.visible ?? false ) return { allEvents, @@ -106,7 +105,7 @@ function toVisibleEvents(allEvents: GithubWorkflowRunEvent[], userSettings: Calc function toVisiblePushes(allEvents: GithubPush[], userSettings: CalculatedUserSettings) { const visibleEvents = allEvents.filter( - ({ ownerId, repoId }) => userSettings.github.accounts.get(ownerId)?.repos.get(repoId)?.visible ?? false + ({ ownerId, repoId }) => userSettings.github.accounts[ownerId]?.repos[repoId]?.visible ?? false ) return { allEvents, diff --git a/src/app/util/collections.ts b/src/app/util/collections.ts index 46c9a95..8d602bd 100644 --- a/src/app/util/collections.ts +++ b/src/app/util/collections.ts @@ -48,14 +48,14 @@ export function removeNullAndUndefined(xs: (T | undefined | null)[]) { return xs.filter((x) => x !== null && x !== undefined) as T[] } -export function getFromMapOrSetNewAndReturn( - map: Map, - key: TKey, +export function getOrSetNewAndReturn( + record: Record, + key: string, getNewValue: () => TValue ): TValue { - const existingValue = map.get(key) + const existingValue = record[key] if (existingValue !== undefined) return existingValue const newValue = getNewValue() - map.set(key, newValue) + record[key] = newValue return newValue } diff --git a/src/app/web/fragments/postUserSetting.ts b/src/app/web/fragments/postUserSetting.ts index 22483bb..3214168 100644 --- a/src/app/web/fragments/postUserSetting.ts +++ b/src/app/web/fragments/postUserSetting.ts @@ -76,7 +76,7 @@ async function processUpdateAccountSetting( const allWorkflows = await getWorkflowsForUser(appState, userId) const updatedSettings = await updateAndSaveAccountSetting(appState, userId, ownerId, setting, enabled) const updatedAccountSettings = - updatedSettings.github.accounts.get(ownerId) ?? + updatedSettings.github.accounts[ownerId] ?? throwFunction('Internal error in processUpdateAccountSetting - no account settings')() return createUpdateUserAccountSettingResponse( @@ -103,7 +103,7 @@ async function processUpdateRepoSetting( const allWorkflows = await getWorkflowsForUser(appState, userId) const newCalculatedUserSettings = calculateUserSettings(newPersistedUserSettings, allWorkflows) const newCalculatedRepoSettings = - newCalculatedUserSettings.github.accounts.get(repoKey.ownerId)?.repos.get(repoKey.repoId) ?? + newCalculatedUserSettings.github.accounts[repoKey.ownerId]?.repos[repoKey.repoId] ?? throwFunction('Internal error in processUpdateRepoSetting - no repo settings')() return createUpdateUserRepoSettingResponse( @@ -126,11 +126,9 @@ async function processUpdateWorkflowSetting( const allWorkflows = await getWorkflowsForUser(appState, userId) const newCalculatedUserSettings = calculateUserSettings(newPersistedUserSettings, allWorkflows) const newCalculatedWorkflowSettings = - newCalculatedUserSettings.github.accounts - .get(workflowKey.ownerId) - ?.repos.get(workflowKey.repoId) - ?.workflows.get(workflowKey.workflowId) ?? - throwFunction('Internal error in processUpdateWorkflowSetting - no workflow settings')() + newCalculatedUserSettings.github.accounts[workflowKey.ownerId]?.repos[workflowKey.repoId]?.workflows[ + workflowKey.workflowId + ] ?? throwFunction('Internal error in processUpdateWorkflowSetting - no workflow settings')() // TODO - think about validating values of IDs diff --git a/src/app/web/fragments/views/getUserSettingsView.ts b/src/app/web/fragments/views/getUserSettingsView.ts index 5c83dd2..d753639 100644 --- a/src/app/web/fragments/views/getUserSettingsView.ts +++ b/src/app/web/fragments/views/getUserSettingsView.ts @@ -16,8 +16,8 @@ export function createGetUserSettingsResponse(settings: DisplayableUserSettings) export function userSettingsElement(settings: DisplayableUserSettings) { const elements = [] - for (const [accountId, accountSettings] of settings.github.accounts) { - elements.push(accountControlsRow(accountId, accountSettings)) + for (const [accountId, accountSettings] of Object.entries(settings.github.accounts)) { + elements.push(accountControlsRow(Number(accountId), accountSettings)) } return elements } @@ -31,8 +31,8 @@ export function accountControlsRow( const repoRows = [] if (accountSettings.visible) { repoRows.push(divRow(colSm(1), colSm(11, b('Repository')))) - for (const [repoId, repoSettings] of accountSettings.repos) { - repoRows.push(repoControlsRow({ ownerId: accountId, repoId }, repoSettings)) + for (const [repoId, repoSettings] of Object.entries(accountSettings.repos)) { + repoRows.push(repoControlsRow({ ownerId: accountId, repoId: Number(repoId) }, repoSettings)) } } @@ -48,8 +48,8 @@ export function repoControlsRow(repoKey: GithubRepoKey, repoSettings: Displayabl const workflowRows: HiccoughElement[] = [] if (repoSettings.visible) { workflowRows.push(divRow(colSm(2), colSm(10, b('Workflow')))) - for (const [workflowId, workflowSettings] of repoSettings.workflows) { - workflowRows.push(workflowControlsRow({ ...repoKey, workflowId }, workflowSettings)) + for (const [workflowId, workflowSettings] of Object.entries(repoSettings.workflows)) { + workflowRows.push(workflowControlsRow({ ...repoKey, workflowId: Number(workflowId) }, workflowSettings)) } } diff --git a/test/local/functional/web/fragments/getUserSettingsFragment.test.ts b/test/local/functional/web/fragments/getUserSettingsFragment.test.ts new file mode 100644 index 0000000..f7b8034 --- /dev/null +++ b/test/local/functional/web/fragments/getUserSettingsFragment.test.ts @@ -0,0 +1,102 @@ +import { expect, test } from 'vitest' +import { FakeAppState } from '../../../../testSupport/fakes/fakeAppState' +import { handleWebRequest } from '../../../../../src/app/lambdaFunctions/authenticatedWeb/lambda' +import { createStubApiGatewayProxyEventWithToken } from '../../../../testSupport/fakes/awsStubs' +import { + stubQueryLatestPushesPerRef, + stubQueryLatestWorkflowRuns, + stubSetupUserRecords +} from '../../../../testSupport/fakes/tableRecordReadStubs' + +test('get-user-settings-html', async () => { + const appState = new FakeAppState() + stubSetupUserRecords(appState) + stubQueryLatestPushesPerRef(appState) + // Used when loading "all workflows" for user settings lookup. Eventually consider adding a workflows entity + stubQueryLatestWorkflowRuns(appState) + + const recentActivity = await handleWebRequest( + appState, + createStubApiGatewayProxyEventWithToken('validUserToken', { + path: '/app/fragment/userSettings', + httpMethod: 'GET' + }) + ) + + expect(recentActivity.statusCode).toEqual(200) + expect(recentActivity.headers).toEqual({ + 'Content-Type': 'text/html' + }) + expect(recentActivity.body).toEqual(`
+

Account: cicada-test-org

+
+
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+
+ Repository +
+
+
+
+
+
+
org-test-repo-one
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ Workflow +
+
+
+
+
Test Repo One Workflow
+
+
+ + +
+
+
+
+ + +
+
+
+
 
+
+
+
`) +}) diff --git a/test/local/unit/domain/entityStore/entities/UserSettingsEntity.test.ts b/test/local/unit/domain/entityStore/entities/UserSettingsEntity.test.ts deleted file mode 100644 index 2e59c84..0000000 --- a/test/local/unit/domain/entityStore/entities/UserSettingsEntity.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect, test } from 'vitest' -import { parseUserSettings } from '../../../../../../src/app/domain/entityStore/entities/UserSettingsEntity' - -test('parser test', () => { - const testValue = { - userId: 111, - github: { - accounts: { - '123': { - repos: { - '456': { - workflows: { - '789': { - visible: true - } - } - } - } - } - } - } - } - - const parsed = parseUserSettings(testValue) - expect(parsed.github.accounts.get(123)?.repos.get(456)?.workflows.get(789)?.visible).toEqual(true) -}) diff --git a/test/local/unit/domain/user/calculatedUserSettings.test.ts b/test/local/unit/domain/user/calculatedUserSettings.test.ts index aabc669..c9266a3 100644 --- a/test/local/unit/domain/user/calculatedUserSettings.test.ts +++ b/test/local/unit/domain/user/calculatedUserSettings.test.ts @@ -8,15 +8,8 @@ import { import { CalculatedVisibleAndNotifyConfigurable, PersistedGithubAccountSettings, - PersistedGithubRepoSettings, - PersistedGithubWorkflowSettings, PersistedVisibleAndNotifyConfigurable } from '../../../../../src/app/domain/types/UserSettings' -import { - GithubAccountId, - GithubRepoId, - GithubWorkflowId -} from '../../../../../src/app/domain/types/GithubKeys' import { USER_ACCOUNT_TYPE } from '../../../../../src/app/domain/types/GithubAccountType' test('calculateVisibleAndNotifyConfigurable / calculateWorkflowSettings', () => { @@ -52,7 +45,7 @@ test('calculateVisibleAndNotifyConfigurable / calculateWorkflowSettings', () => test('repo settings when no workflow settings', () => { const calculated = calculateRepoSettings( - { workflows: new Map() }, + { workflows: {} }, { ownerId: 123, repoId: 456 }, [ { @@ -68,17 +61,22 @@ test('repo settings when no workflow settings', () => { ], true ) - expect(calculated.visible).toEqual(true) - expect(calculated.notify).toEqual(true) - expect(calculated.workflows.size).toEqual(1) - expect(calculated.workflows.get(789)).toEqual({ visible: true, notify: true }) + + expect(calculated).toEqual({ + visible: true, + notify: true, + workflows: { + 789: { + visible: true, + notify: true + } + } + }) }) test('repo settings when workflow settings', () => { - const workflows = new Map() - workflows.set(789, { notify: false }) const calculated = calculateRepoSettings( - { workflows }, + { workflows: { 789: { notify: false } } }, { ownerId: 123, repoId: 456 }, [ { @@ -94,17 +92,22 @@ test('repo settings when workflow settings', () => { ], true ) - expect(calculated.visible).toEqual(true) - expect(calculated.notify).toEqual(true) - expect(calculated.workflows.size).toEqual(1) - expect(calculated.workflows.get(789)).toEqual({ visible: true, notify: false }) + + expect(calculated).toEqual({ + visible: true, + notify: true, + workflows: { + 789: { + visible: true, + notify: false + } + } + }) }) test('repo settings when visible false', () => { - const workflows = new Map() - workflows.set(789, { notify: false }) const calculated = calculateRepoSettings( - { workflows, visible: false }, + { workflows: { 789: { notify: false } }, visible: false }, { ownerId: 123, repoId: 456 }, [ { @@ -120,17 +123,24 @@ test('repo settings when visible false', () => { ], true ) - expect(calculated.visible).toEqual(false) - expect(calculated.notify).toEqual(false) - expect(calculated.workflows.size).toEqual(0) + + expect(calculated).toEqual({ + visible: false, + notify: false, + workflows: {} + }) }) test('repo settings when visible true notify false', () => { - const workflows = new Map() - workflows.set(789, { notify: true }) - workflows.set(790, {}) const calculated = calculateRepoSettings( - { workflows, visible: true, notify: false }, + { + workflows: { + 789: { notify: true }, + 790: {} + }, + visible: true, + notify: false + }, { ownerId: 123, repoId: 456 }, [ { @@ -156,11 +166,15 @@ test('repo settings when visible true notify false', () => { ], true ) - expect(calculated.visible).toEqual(true) - expect(calculated.notify).toEqual(false) - expect(calculated.workflows.size).toEqual(2) - expect(calculated.workflows.get(789)).toEqual({ visible: true, notify: true }) - expect(calculated.workflows.get(790)).toEqual({ visible: true, notify: false }) + + expect(calculated).toEqual({ + visible: true, + notify: false, + workflows: { + 789: { visible: true, notify: true }, + 790: { visible: true, notify: false } + } + }) }) test('account settings when none persisted', () => { @@ -187,28 +201,46 @@ test('account settings when none persisted', () => { } ]) - expect(calculated.visible).toEqual(true) - expect(calculated.notify).toEqual(true) - expect(calculated.repos.size).toEqual(2) - expect(calculated.repos.get(123)?.visible).toEqual(true) - expect(calculated.repos.get(123)?.notify).toEqual(true) - expect(calculated.repos.get(456)?.visible).toEqual(true) - expect(calculated.repos.get(456)?.notify).toEqual(true) + expect(calculated).toEqual({ + visible: true, + notify: true, + repos: { + 123: { + visible: true, + notify: true, + workflows: { + 789: { + notify: true, + visible: true + } + } + }, + 456: { + visible: true, + notify: true, + workflows: { + 790: { + notify: true, + visible: true + } + } + } + } + }) }) test('account settings ', () => { - const persistedRepos = new Map() - persistedRepos.set(123, { - workflows: new Map() - }) - persistedRepos.set(456, { - visible: false, - notify: false, - workflows: new Map() - }) - const persistedAccountSettings: PersistedGithubAccountSettings = { - repos: persistedRepos + repos: { + 123: { + workflows: {} + }, + 456: { + visible: false, + notify: false, + workflows: {} + } + } } const calculated = calculateAccountSettings(persistedAccountSettings, 111, [ @@ -234,13 +266,27 @@ test('account settings ', () => { } ]) - expect(calculated.visible).toEqual(true) - expect(calculated.notify).toEqual(true) - expect(calculated.repos.size).toEqual(2) - expect(calculated.repos.get(123)?.visible).toEqual(true) - expect(calculated.repos.get(123)?.notify).toEqual(true) - expect(calculated.repos.get(456)?.visible).toEqual(false) - expect(calculated.repos.get(456)?.notify).toEqual(false) + expect(calculated).toEqual({ + visible: true, + notify: true, + repos: { + 123: { + visible: true, + notify: true, + workflows: { + 789: { + notify: true, + visible: true + } + } + }, + 456: { + visible: false, + notify: false, + workflows: {} + } + } + }) }) test('user settings when empty persisted', () => { @@ -248,7 +294,7 @@ test('user settings when empty persisted', () => { { userId: 222, github: { - accounts: new Map() + accounts: {} } }, [ @@ -275,33 +321,57 @@ test('user settings when empty persisted', () => { ] ) - expect(calculated.github.accounts.get(111)?.visible).toEqual(true) - expect(calculated.github.accounts.get(111)?.notify).toEqual(true) - expect(calculated.github.accounts.get(111)?.repos.size).toEqual(2) - expect(calculated.github.accounts.get(111)?.repos.get(123)?.visible).toEqual(true) - expect(calculated.github.accounts.get(111)?.repos.get(123)?.notify).toEqual(true) - expect(calculated.github.accounts.get(111)?.repos.get(456)?.visible).toEqual(true) - expect(calculated.github.accounts.get(111)?.repos.get(456)?.notify).toEqual(true) + expect(calculated).toEqual({ + userId: 222, + github: { + accounts: { + 111: { + visible: true, + notify: true, + repos: { + 123: { + visible: true, + notify: true, + workflows: { + 789: { + notify: true, + visible: true + } + } + }, + 456: { + visible: true, + notify: true, + workflows: { + 790: { + notify: true, + visible: true + } + } + } + } + } + } + } + }) }) test('user settings when some persisted', () => { - const persistedRepos = new Map() - persistedRepos.set(456, { - visible: false, - notify: false, - workflows: new Map() - }) - - const persistedAccounts = new Map() - persistedAccounts.set(111, { - repos: persistedRepos - }) - const calculated = calculateUserSettings( { userId: 222, github: { - accounts: persistedAccounts + accounts: { + 111: { + repos: { + 456: { + visible: false, + notify: false, + workflows: {} + } + } + } + } } }, [ @@ -328,11 +398,32 @@ test('user settings when some persisted', () => { ] ) - expect(calculated.github.accounts.get(111)?.visible).toEqual(true) - expect(calculated.github.accounts.get(111)?.notify).toEqual(true) - expect(calculated.github.accounts.get(111)?.repos.size).toEqual(2) - expect(calculated.github.accounts.get(111)?.repos.get(123)?.visible).toEqual(true) - expect(calculated.github.accounts.get(111)?.repos.get(123)?.notify).toEqual(true) - expect(calculated.github.accounts.get(111)?.repos.get(456)?.visible).toEqual(false) - expect(calculated.github.accounts.get(111)?.repos.get(456)?.notify).toEqual(false) + expect(calculated).toEqual({ + userId: 222, + github: { + accounts: { + 111: { + visible: true, + notify: true, + repos: { + 123: { + visible: true, + notify: true, + workflows: { + 789: { + notify: true, + visible: true + } + } + }, + 456: { + visible: false, + notify: false, + workflows: {} + } + } + } + } + } + }) }) diff --git a/test/local/unit/domain/user/displayableUserSettings.test.ts b/test/local/unit/domain/user/displayableUserSettings.test.ts new file mode 100644 index 0000000..401bef4 --- /dev/null +++ b/test/local/unit/domain/user/displayableUserSettings.test.ts @@ -0,0 +1,190 @@ +import { expect, test } from 'vitest' +import { USER_ACCOUNT_TYPE } from '../../../../../src/app/domain/types/GithubAccountType' +import { + toCalculatedAndDisplayableUserSettings, + toDisplayableAccountSettings, + toDisplayableRepoSettings, + toDisplayableWorkflowSettings +} from '../../../../../src/app/domain/user/displayableUserSettings' + +test('toDisplayableWorkflowSettings', () => { + const displayable = toDisplayableWorkflowSettings( + { ownerId: 123, repoId: 456, workflowId: 789 }, + { + visible: true, + notify: true + }, + [ + { + ownerId: 123, + repoId: 456, + workflowId: 789, + workflowName: 'workflow1', + ownerType: USER_ACCOUNT_TYPE, + ownerName: '', + repoName: '', + path: '' + } + ] + ) + + expect(displayable).toEqual({ + visible: true, + notify: true, + name: 'workflow1' + }) +}) + +test('toDisplayableRepoSettings', () => { + const displayable = toDisplayableRepoSettings( + { ownerId: 123, repoId: 456 }, + { + visible: true, + notify: true, + workflows: { + 789: { + visible: true, + notify: true + } + } + }, + [ + { + ownerId: 123, + repoId: 456, + workflowId: 789, + workflowName: 'workflow1', + ownerType: USER_ACCOUNT_TYPE, + ownerName: '', + repoName: 'repo1', + path: '' + } + ] + ) + + expect(displayable).toEqual({ + name: 'repo1', + visible: true, + notify: true, + workflows: { + 789: { + visible: true, + notify: true, + name: 'workflow1' + } + } + }) +}) + +test('toDisplayableAccountSettings', () => { + const displayable = toDisplayableAccountSettings( + 123, + { + visible: true, + notify: true, + repos: { + 456: { + visible: true, + notify: true, + workflows: { + 789: { + visible: true, + notify: true + } + } + } + } + }, + [ + { + ownerId: 123, + repoId: 456, + workflowId: 789, + workflowName: 'workflow1', + ownerType: USER_ACCOUNT_TYPE, + ownerName: 'account1', + repoName: 'repo1', + path: '' + } + ] + ) + + expect(displayable).toEqual({ + name: 'account1', + visible: true, + notify: true, + repos: { + 456: { + name: 'repo1', + visible: true, + notify: true, + workflows: { + 789: { + visible: true, + notify: true, + name: 'workflow1' + } + } + } + } + }) +}) + +test('toCalculatedAndDisplayableUserSettings', () => { + const displayable = toCalculatedAndDisplayableUserSettings( + { + userId: 111, + github: { + accounts: { + 123: { + repos: { + 456: { + notify: false, + workflows: {} + } + } + } + } + } + }, + [ + { + ownerId: 123, + repoId: 456, + workflowId: 789, + workflowName: 'workflow1', + ownerType: USER_ACCOUNT_TYPE, + ownerName: 'account1', + repoName: 'repo1', + path: '' + } + ] + ) + + expect(displayable).toEqual({ + userId: 111, + github: { + accounts: { + 123: { + name: 'account1', + visible: true, + notify: true, + repos: { + 456: { + name: 'repo1', + visible: true, + notify: false, + workflows: { + 789: { + visible: true, + notify: false, + name: 'workflow1' + } + } + } + } + } + } + } + }) +}) diff --git a/test/local/unit/domain/user/persistedUserSettings.test.ts b/test/local/unit/domain/user/persistedUserSettings.test.ts index 9a51764..58639b7 100644 --- a/test/local/unit/domain/user/persistedUserSettings.test.ts +++ b/test/local/unit/domain/user/persistedUserSettings.test.ts @@ -4,75 +4,74 @@ import { repoUpdater, workflowUpdater } from '../../../../../src/app/domain/user/persistedUserSettings' -import { - GithubAccountId, - GithubRepoId, - GithubUserId, - GithubWorkflowId -} from '../../../../../src/app/domain/types/GithubKeys' -import { - PersistedGithubAccountSettings, - PersistedGithubRepoSettings, - PersistedGithubWorkflowSettings, - PersistedUserSettings -} from '../../../../../src/app/domain/types/UserSettings' +import { GithubUserId } from '../../../../../src/app/domain/types/GithubKeys' +import { PersistedUserSettings } from '../../../../../src/app/domain/types/UserSettings' function emptySettings(userId: GithubUserId): PersistedUserSettings { return { userId, github: { - accounts: new Map() + accounts: {} } } } test('update settings new account', () => { const newSettings = accountUpdater(123, 'visible', true)(emptySettings(11)) - - expect(newSettings.github.accounts.get(123)?.notify).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.visible).toEqual(true) + expect(newSettings.github.accounts).toEqual({ + 123: { + visible: true, + repos: {} + } + }) }) test('update settings existing account', () => { const settings = emptySettings(11) - const accountSettings: PersistedGithubAccountSettings = { + settings.github.accounts[123] = { notify: true, - repos: new Map() + repos: {} } - settings.github.accounts.set(123, accountSettings) const newSettings = accountUpdater(123, 'visible', true)(settings) - expect(newSettings.github.accounts.get(123)?.notify).toEqual(true) - expect(newSettings.github.accounts.get(123)?.visible).toEqual(true) + expect(newSettings.github.accounts).toEqual({ + 123: { + notify: true, + visible: true, + repos: {} + } + }) }) test('update settings new repo', () => { const newSettings = repoUpdater({ ownerId: 123, repoId: 456 }, 'visible', true)(emptySettings(11)) - - expect(newSettings.github.accounts.get(123)?.notify).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.visible).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.notify).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.visible).toEqual(true) + expect(newSettings.github.accounts[123]).toEqual({ + repos: { + 456: { + visible: true, + workflows: {} + } + } + }) }) test('update settings existing repo', () => { - const repos = new Map() - repos.set(456, { - notify: true, - workflows: new Map() - }) - const accountSettings: PersistedGithubAccountSettings = { + const settings = emptySettings(11) + settings.github.accounts[123] = { notify: true, - repos + repos: { + 456: { + notify: true, + workflows: {} + } + } } - const settings = emptySettings(11) - settings.github.accounts.set(123, accountSettings) const newSettings = repoUpdater({ ownerId: 123, repoId: 456 }, 'visible', true)(settings) - expect(newSettings.github.accounts.get(123)?.notify).toEqual(true) - expect(newSettings.github.accounts.get(123)?.visible).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.notify).toEqual(true) - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.visible).toEqual(true) + expect(newSettings.github.accounts[123]).toEqual({ + notify: true, + repos: { 456: { notify: true, visible: true, workflows: {} } } + }) }) test('update settings new workflow', () => { @@ -82,40 +81,57 @@ test('update settings new workflow', () => { true )(emptySettings(11)) - expect(newSettings.github.accounts.get(123)?.notify).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.visible).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.notify).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.visible).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.workflows.get(789)?.notify).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.workflows.get(789)?.visible).toEqual(true) + expect(newSettings.github.accounts).toEqual({ + 123: { + repos: { + 456: { + workflows: { + 789: { + visible: true + } + } + } + } + } + }) }) test('update settings existing repo', () => { - const workflows = new Map() - workflows.set(789, { - notify: true - }) - const repos = new Map() - repos.set(456, { - notify: true, - workflows: workflows - }) - const accountSettings: PersistedGithubAccountSettings = { + const settings = emptySettings(11) + settings.github.accounts[123] = { notify: true, - repos + repos: { + 456: { + notify: true, + workflows: { + 789: { + notify: true + } + } + } + } } - const settings = emptySettings(11) - settings.github.accounts.set(123, accountSettings) const newSettings = workflowUpdater( { ownerId: 123, repoId: 456, workflowId: 789 }, 'visible', true )(settings) - expect(newSettings.github.accounts.get(123)?.notify).toEqual(true) - expect(newSettings.github.accounts.get(123)?.visible).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.notify).toEqual(true) - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.visible).toBeUndefined() - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.workflows.get(789)?.notify).toEqual(true) - expect(newSettings.github.accounts.get(123)?.repos.get(456)?.workflows.get(789)?.visible).toEqual(true) + + expect(newSettings.github.accounts).toEqual({ + 123: { + notify: true, + repos: { + 456: { + notify: true, + workflows: { + 789: { + notify: true, + visible: true + } + } + } + } + } + }) })