-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Integration test
- Loading branch information
Showing
12 changed files
with
276 additions
and
31 deletions.
There are no files selected for viewing
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
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
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
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
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,12 +1,104 @@ | ||
// TODO [#35]: Add integration test for TodoActionsMain. | ||
// | ||
// Code that interface with external data have been separated into their own modules. | ||
// These includes: | ||
// | ||
// - `DataStore` | ||
// - `CodeRepository` | ||
// - `TaskManagementSystem` | ||
// | ||
// They can be mocked by creating a mock version using `__mocks__` folder. | ||
// https://jestjs.io/docs/en/manual-mocks | ||
test.todo('works') | ||
import { runMain } from './TodoActionsMain' | ||
import { resetMockWorld } from './__mocks__/World' | ||
import sortBy from 'lodash.sortby' | ||
|
||
jest.mock('./DataStore') | ||
jest.mock('./CodeRepository') | ||
jest.mock('./TaskManagementSystem') | ||
|
||
const MARKER = 'TODO' | ||
|
||
it('works', async () => { | ||
const world = resetMockWorld() | ||
|
||
// Round 1: Arrange | ||
world.file( | ||
'main.js', | ||
` | ||
// ${MARKER}: Hello world | ||
// This is great! | ||
<!-- | ||
- ${MARKER}: | ||
- Somebody once told me | ||
- the world is gonna roll me | ||
--> | ||
`, | ||
) | ||
|
||
// Round 1: Act | ||
await runMain() | ||
|
||
// Round 1: Assert commits | ||
expect(world.commits.length).toEqual(2) | ||
expect(world.commits[0].files.get('main.js')).toMatch( | ||
new RegExp(`${MARKER} \\[\\$\\w+\\]: Hello world`), | ||
) | ||
expect(world.commits[1].files.get('main.js')).toMatch( | ||
new RegExp(`${MARKER} \\[#\\d+\\]: Hello world`), | ||
) | ||
|
||
// Round 1: Assert tasks | ||
expect(world.tasks.length).toEqual(2) | ||
expect(sortBy(world.tasks.map(t => t.title))).toEqual([ | ||
'Hello world', | ||
'Somebody once told me', | ||
]) | ||
|
||
// Idempotent check | ||
await runMain() | ||
expect(world.commits.length).toEqual(2) | ||
expect(world.tasks.length).toEqual(2) | ||
|
||
// Round 2: Arrange | ||
const task1 = world.tasks.find(t => t.title === 'Hello world')! | ||
const task2 = world.tasks.find(t => t.title === 'Somebody once told me')! | ||
world.file( | ||
'main.js', | ||
` | ||
<!-- | ||
- ${MARKER} [#${task2.number}]: | ||
- Somebody once told me? | ||
- the world is gonna roll me | ||
--> | ||
`, | ||
) | ||
|
||
// Round 2: Act | ||
await runMain() | ||
|
||
// Round 2: Assert commits | ||
// No new commits expected | ||
expect(world.commits.length).toEqual(2) | ||
|
||
// Round 2: Assert tasks | ||
expect(task1.completed).toBe(true) | ||
expect(task2.completed).toBe(false) | ||
expect(task2.title).toBe('Somebody once told me?') | ||
}) | ||
|
||
it('skips non default branch', async () => { | ||
const world = resetMockWorld() | ||
|
||
// Arrange | ||
world.branch = 'featureBranch' | ||
world.file( | ||
'main.js', | ||
` | ||
// ${MARKER}: Hello world | ||
// This is great! | ||
<!-- | ||
- ${MARKER}: | ||
- Somebody once told me | ||
- the world is gonna roll me | ||
--> | ||
`, | ||
) | ||
|
||
// Act | ||
await runMain() | ||
|
||
// Assert | ||
expect(world.commits.length).toEqual(0) | ||
}) |
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
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 |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { mockWorld } from './World' | ||
|
||
type Real = typeof import('../CodeRepository') | ||
|
||
export const repoContext: Real['repoContext'] = { | ||
repositoryNodeId: '__GITHUB_REPO_NODE_ID__', | ||
repositoryOwner: '_dtinth', | ||
repositoryName: '_todo-actions', | ||
defaultBranch: 'master', | ||
} | ||
|
||
export const scanCodeRepository: Real['scanCodeRepository'] = async () => { | ||
const files = [...mockWorld.files.values()] | ||
return { | ||
files: files, | ||
isOnDefaultBranch: mockWorld.branch === repoContext.defaultBranch, | ||
async saveChanges(commitMessage) { | ||
if (!files.some(f => f.contents.changed)) return | ||
files.forEach(f => f.save()) | ||
mockWorld.commits.push({ | ||
message: commitMessage, | ||
files: new Map(files.map(f => [f.fileName, f.contents.toString()])), | ||
}) | ||
}, | ||
} | ||
} |
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 |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { mockWorld } from './World' | ||
|
||
type Real = typeof import('../DataStore') | ||
|
||
export const beginTaskResolution: Real['beginTaskResolution'] = async ( | ||
todoUniqueKey, | ||
repositoryId, | ||
) => { | ||
const existing = mockWorld.store.find(entry => entry._id === todoUniqueKey) | ||
if (existing) { | ||
return { existingTaskReference: existing.reference } | ||
} | ||
|
||
return { | ||
async acquireTaskCreationLock() { | ||
return { | ||
async finish(taskReference, state) { | ||
mockWorld.store.push({ | ||
_id: todoUniqueKey, | ||
reference: taskReference, | ||
state: state, | ||
completed: false, | ||
}) | ||
}, | ||
} | ||
}, | ||
} | ||
} | ||
|
||
export const findAllUncompletedTasks: Real['findAllUncompletedTasks'] = async repositoryId => { | ||
return mockWorld.store | ||
.filter(entry => !entry.completed) | ||
.map(entry => { | ||
return { | ||
taskReference: entry.reference, | ||
state: entry.state, | ||
async markAsCompleted() { | ||
entry.completed = true | ||
}, | ||
async updateState(newState) { | ||
entry.state = newState | ||
}, | ||
} | ||
}) | ||
} |
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 |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { mockWorld, MockTask } from './World' | ||
|
||
type Real = typeof import('../TaskManagementSystem') | ||
|
||
export const createTask: Real['createTask'] = async information => { | ||
const number = mockWorld.tasks.length + 1 | ||
const task: MockTask = { ...information, number, completed: false } | ||
mockWorld.tasks.push(task) | ||
return `#${task.number}` | ||
} | ||
|
||
export const completeTask: Real['completeTask'] = async taskReference => { | ||
getTask(taskReference).completed = true | ||
} | ||
|
||
export const updateTask: Real['updateTask'] = async ( | ||
taskReference, | ||
information, | ||
) => { | ||
Object.assign(getTask(taskReference), information) | ||
} | ||
|
||
function getTask(taskReference: string) { | ||
return mockWorld.tasks.find(t => `#${t.number}` === taskReference)! | ||
} |
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 |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { IFile, ITaskState } from '../types' | ||
import { MockFile } from '../File' | ||
|
||
export let mockWorld: MockWorld | ||
|
||
export type MockTask = { | ||
title: string | ||
body: string | ||
number: number | ||
completed: boolean | ||
} | ||
|
||
export type MockDataStoreEntry = { | ||
_id: string | ||
completed: boolean | ||
reference: string | ||
state: ITaskState | ||
} | ||
|
||
export type MockCommit = { | ||
message: string | ||
files: Map<string, string> | ||
} | ||
|
||
export function resetMockWorld() { | ||
mockWorld = new MockWorld() | ||
return mockWorld | ||
} | ||
|
||
class MockWorld { | ||
files: Map<string, IFile> = new Map() | ||
branch = 'master' | ||
store: MockDataStoreEntry[] = [] | ||
tasks: MockTask[] = [] | ||
commits: MockCommit[] = [] | ||
|
||
file(fileName: string, contents: string) { | ||
this.files.set(fileName, new MockFile(fileName, contents)) | ||
} | ||
} |
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
Oops, something went wrong.