-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial take on refactoring to store and client * connect section title to store * make the app use localStorage * remote IStore interface to simplify. fix workflow test command * use typed in username for comments * add import for index.css
- Loading branch information
1 parent
571c1b0
commit bc5af78
Showing
25 changed files
with
1,002 additions
and
261 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"extends": [ | ||
"react-app", | ||
"react-app/jest" | ||
], | ||
"rules": { | ||
"testing-library/no-container": "off", | ||
"testing-library/no-node-access": "off" | ||
} | ||
} |
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,16 +1,201 @@ | ||
import { render, screen } from '@testing-library/react'; | ||
import * as testData from './sampleData' | ||
import {render, screen, waitFor} from '@testing-library/react'; | ||
import App from './App'; | ||
import {IClient} from './client/IClient'; | ||
import {ProjectData, CommentData, SectionData, EntityType, FileData} from './types'; | ||
import {LocalStorageStore, StoreData} from './store/LocalStorageStore'; | ||
import {MockLocalStorageDependency} from './store/MockLocalStorageDependency'; | ||
import {LocalStorageClient} from './client/LocalStorageClient'; | ||
|
||
test('renders learn react link', () => { | ||
render( | ||
<App | ||
sectionData={testData.sectionData} | ||
chordProgression={testData.currentChordProgression} | ||
files={testData.files} | ||
comments={testData.comments} | ||
/> | ||
); | ||
const linkElement = screen.getByText(/learn react/i); | ||
expect(linkElement).toBeInTheDocument(); | ||
// import * as testData from './sampleData' | ||
|
||
window.alert = () => {}; | ||
|
||
const makeTestStore = (): StoreData => { | ||
const initialProjects: ProjectData[] = [ | ||
{ | ||
id: 'project-1', | ||
}, | ||
{ | ||
id: 'project-2', | ||
}, | ||
]; | ||
|
||
const initialSections: SectionData[] = [ | ||
{ | ||
id: 'section-1', | ||
projectId: 'project-1', | ||
chordProgression: ['C', 'Dm', 'F', 'G'], | ||
description: 'This is the intro', | ||
title: 'Intro', | ||
numRevisions: 3, | ||
} | ||
]; | ||
|
||
const initialFiles: FileData[] = [ | ||
{ | ||
id: 'file-1', | ||
projectId: 'project-1', | ||
entityId: 'section-1', | ||
entityType: EntityType.SECTION, | ||
title: 'Bass.mp3', | ||
}, | ||
{ | ||
id: 'file-2', | ||
projectId: 'project-1', | ||
entityId: 'section-1', | ||
entityType: EntityType.SECTION, | ||
title: 'Chunky Monkey.mp3', | ||
}, | ||
]; | ||
|
||
const initialComments: CommentData[] = [ | ||
{ | ||
id: 'comment-1', | ||
projectId: 'project-1', | ||
message: 'Hey what\'s up', | ||
entityType: EntityType.SECTION, | ||
entityId: 'section-1', | ||
username: 'username-1', | ||
}, | ||
{ | ||
id: 'comment-2', | ||
projectId: 'project-1', | ||
message: 'Yeah', | ||
entityType: EntityType.FILE, | ||
entityId: 'file-1', | ||
username: 'username-1', | ||
}, | ||
{ | ||
id: 'comment-3', | ||
projectId: 'project-1', | ||
message: 'Yeah 3', | ||
entityType: EntityType.FILE, | ||
entityId: 'file-1', | ||
username: 'username-1', | ||
}, | ||
]; | ||
|
||
return { | ||
projects: initialProjects, | ||
sections: initialSections, | ||
files: initialFiles, | ||
comments: initialComments, | ||
}; | ||
}; | ||
|
||
describe('App', () => { | ||
let client: IClient; | ||
|
||
beforeEach(() => { | ||
const initialStore = makeTestStore(); | ||
|
||
const localStorageDependency = new MockLocalStorageDependency(initialStore); | ||
const store = new LocalStorageStore(localStorageDependency); | ||
client = new LocalStorageClient(store); | ||
}); | ||
|
||
describe('initializing', () => { | ||
it('should show "Loading"', async () => { | ||
// this method is made blocking for this specific test | ||
client.fetchFullDataForProject = (() => new Promise(r => setTimeout(r))); | ||
|
||
render( | ||
<App | ||
projectId={'project-1'} | ||
sectionId={'section-1'} | ||
client={client} | ||
/> | ||
); | ||
|
||
expect(screen.getByText(/Loading/)).toBeDefined(); | ||
}); | ||
|
||
it('should show client error', async () => { | ||
client.fetchFullDataForProject = jest.fn().mockResolvedValue(new Error('Some error')); | ||
|
||
render( | ||
<App | ||
projectId={'project-1'} | ||
sectionId={'section-1'} | ||
client={client} | ||
/> | ||
); | ||
|
||
await waitFor(() => { | ||
expect(screen.queryByText(/Loading/)).toBeNull(); | ||
}); | ||
|
||
expect(screen.getByText(/Some error/)).toBeDefined(); | ||
}); | ||
}); | ||
|
||
describe('initialized', () => { | ||
it('should show the section title and description', async () => { | ||
render( | ||
<App | ||
projectId={'project-1'} | ||
sectionId={'section-1'} | ||
client={client} | ||
/> | ||
); | ||
|
||
await waitFor(() => { | ||
expect(screen.queryByText(/Loading/)).toBeNull(); | ||
}); | ||
|
||
expect(screen.getByText(/Intro/)).toBeDefined(); | ||
expect(screen.getByText(/This is the intro/)).toBeDefined(); | ||
}); | ||
|
||
it('should show the chord progression', async () => { | ||
const {container} = render( | ||
<App | ||
projectId={'project-1'} | ||
sectionId={'section-1'} | ||
client={client} | ||
/> | ||
); | ||
|
||
await waitFor(() => { | ||
expect(screen.queryByText(/Loading/)).toBeNull(); | ||
}); | ||
|
||
expect(container.querySelector('.chords')?.textContent).toEqual('CDmFG'); | ||
}); | ||
|
||
it('should show files attached to the section', async () => { | ||
const {container} = render( | ||
<App | ||
projectId={'project-1'} | ||
sectionId={'section-1'} | ||
client={client} | ||
/> | ||
); | ||
|
||
await waitFor(() => { | ||
expect(screen.queryByText(/Loading/)).toBeNull(); | ||
}); | ||
|
||
expect(container.querySelector('.files #file-1')?.textContent).toContain('Bass.mp3'); | ||
expect(container.querySelector('.files #file-1')?.textContent).toContain('2 Comments'); | ||
}); | ||
|
||
it('should show the comments on the section', async () => { | ||
const {container} = render( | ||
<App | ||
projectId={'project-1'} | ||
sectionId={'section-1'} | ||
client={client} | ||
/> | ||
); | ||
|
||
await waitFor(() => { | ||
expect(screen.queryByText(/Loading/)).toBeNull(); | ||
}); | ||
|
||
expect(container.querySelector('.comments')?.textContent).toContain('1 Comment'); | ||
expect(container.querySelector('.comments #comment-1')?.textContent).toContain('username-1'); | ||
expect(container.querySelector('.comments #comment-1')?.textContent).toContain('Hey what\'s up'); | ||
}); | ||
}); | ||
}); |
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,38 +1,69 @@ | ||
import {useState} from 'react'; | ||
|
||
import './App.css'; | ||
import './css_reset.css' | ||
import './index.css' | ||
import './section_view.css'; | ||
import * as types from './types'; | ||
import { Files } from './Files'; | ||
import { ChordProgression } from './ChordProgression'; | ||
import { Comments } from './Comments'; | ||
import { CreateComment } from './CreateComment'; | ||
import { SectionTitle } from './SectionTitle'; | ||
import { useState } from 'react'; | ||
import {GlobalStoreProvider} from './hooks/useGlobalStore'; | ||
import SectionPage from './SectionPage'; | ||
import {IClient} from './client/IClient'; | ||
import {ClientProvider} from './hooks/useClient'; | ||
import {useMount} from './hooks/useMount'; | ||
|
||
type AppProps = { | ||
projectId: string; | ||
sectionId: string; | ||
|
||
client: IClient; | ||
} | ||
|
||
const App: React.FC<AppProps> = ({projectId, sectionId, client}) => { | ||
const [initialProjectData, setInitialProjectData] = useState<types.FullProjectData | null>(null); | ||
const [error, setError] = useState(''); | ||
|
||
type AppProps = { | ||
sectionData: types.SectionData, | ||
chordProgression: types.ChordProgression, | ||
files: types.File[], | ||
comments: types.Comment[] | ||
} | ||
useMount(async () => { | ||
const projectDataOrError = await client.fetchFullDataForProject(projectId); | ||
|
||
if (projectDataOrError instanceof Error) { | ||
alert(projectDataOrError.message); | ||
setError(projectDataOrError.message); | ||
return; | ||
} | ||
|
||
setInitialProjectData(projectDataOrError); | ||
}); | ||
|
||
if (error) { | ||
return ( | ||
<p> | ||
{error} | ||
</p> | ||
); | ||
} | ||
|
||
const App:React.FC<AppProps> = ({sectionData, chordProgression, comments, files}) => { | ||
if (!initialProjectData) { | ||
return ( | ||
<p> | ||
Loading | ||
</p> | ||
); | ||
} | ||
|
||
const [commentsAsState, setCommentsAsState] = useState<types.Comment[]>(comments) | ||
|
||
const pageContent = ( | ||
<SectionPage | ||
projectId={projectId} | ||
sectionId={sectionId} | ||
/> | ||
); | ||
|
||
return ( | ||
<div className="root"> | ||
<SectionTitle sectionData={sectionData} /> | ||
<ChordProgression chordProgression={chordProgression} /> | ||
<Files files={files}/> | ||
<Comments comments={commentsAsState} setComments={setCommentsAsState}/> | ||
<CreateComment comments={commentsAsState} setComments={setCommentsAsState}/> | ||
</div> | ||
); | ||
return ( | ||
<ClientProvider client={client}> | ||
<GlobalStoreProvider initialProjectData={initialProjectData}> | ||
{pageContent} | ||
</GlobalStoreProvider> | ||
</ClientProvider> | ||
); | ||
} | ||
|
||
export default App; |
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.