Skip to content

Commit

Permalink
Merge 09f5358 into 5087629
Browse files Browse the repository at this point in the history
  • Loading branch information
ctaylo21 committed Apr 18, 2020
2 parents 5087629 + 09f5358 commit 621fb82
Show file tree
Hide file tree
Showing 28 changed files with 1,396 additions and 255 deletions.
318 changes: 233 additions & 85 deletions docs/demo.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/demo.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
width: 24px; }
#terminal-wrapper .preview-list span {
margin: 0px 10px; }
#terminal-wrapper .preview-list span.ls-preview-folder {
#terminal-wrapper .preview-list span.auto-preview-folder {
color: #f99157; }
#terminal-wrapper .preview-list span.ls-preview-file {
#terminal-wrapper .preview-list span.auto-preview-file {
color: #5fb3b3; }
#terminal-wrapper .preview-list span.active {
background-color: #4F5B66; }
12 changes: 10 additions & 2 deletions src/__tests__/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`autocomplete with tab ls ls tab with argument and relative nested path 1`] = `"<div class=\\"preview-list\\"><span class=\\"ls-preview-file\\">file1.txt</span><span class=\\"ls-preview-file\\">file5.txt</span></div>"`;
exports[`autocomplete with tab ls ls tab with argument and relative nested path 1`] = `"<div class=\\"preview-list\\"><span class=\\"auto-preview-file\\">file1.txt</span><span class=\\"auto-preview-file\\">file5.txt</span></div>"`;
exports[`autocomplete with tab ls ls tab with no argument 1`] = `"<div class=\\"preview-list\\"><span class=\\"ls-preview-folder\\">home/</span><span class=\\"ls-preview-folder\\">docs/</span><span class=\\"ls-preview-file\\">file3.txt</span><span class=\\"ls-preview-file\\">file4.txt</span><span class=\\"ls-preview-file\\">blog.txt</span></div>"`;
exports[`autocomplete with tab ls ls tab with no argument 1`] = `"<div class=\\"preview-list\\"><span class=\\"auto-preview-folder\\">home/</span><span class=\\"auto-preview-folder\\">docs/</span><span class=\\"auto-preview-file\\">file3.txt</span><span class=\\"auto-preview-file\\">file4.txt</span><span class=\\"auto-preview-file\\">blog.txt</span></div>"`;
exports[`autocomplete with tab rm rm tab with argument and relative nested path 1`] = `"<div class=\\"preview-list\\"><span class=\\"auto-preview-file\\">file1.txt</span><span class=\\"auto-preview-file\\">file5.txt</span></div>"`;
exports[`autocomplete with tab rm rm tab with no target but command args 1`] = `"<div class=\\"preview-list\\"><span class=\\"auto-preview-folder\\">home/</span><span class=\\"auto-preview-folder\\">docs/</span><span class=\\"auto-preview-file\\">file3.txt</span><span class=\\"auto-preview-file\\">file4.txt</span><span class=\\"auto-preview-file\\">blog.txt</span></div>"`;
exports[`cat should handle cat with no space 1`] = `"<li><div id=\\"input-container\\" spellcheck=\\"false\\"><form><span data-testid=\\"input-prompt-path\\">/</span>&nbsp;<span id=\\"inputPrompt\\">$&gt;</span><input aria-label=\\"terminal-input\\" autocomplete=\\"none\\" autocapitalize=\\"none\\" autocorrect=\\"off\\" type=\\"text\\" readonly=\\"\\" value=\\"cat\\"></form></div><span class=\\"commandResult\\">Error: Invalid target path</span></li>"`;
exports[`cat should list contents of file that contains react component 1`] = `"<li><div id=\\"input-container\\" spellcheck=\\"false\\"><form><span data-testid=\\"input-prompt-path\\">/</span>&nbsp;<span id=\\"inputPrompt\\">$&gt;</span><input aria-label=\\"terminal-input\\" autocomplete=\\"none\\" autocapitalize=\\"none\\" autocorrect=\\"off\\" type=\\"text\\" readonly=\\"\\" value=\\"cat blog.txt\\"></form></div><span class=\\"commandResult\\"><h3>3/22</h3><p>Today is a good day</p></span></li>"`;
Expand All @@ -26,6 +32,8 @@ exports[`cd should support cd with absolute path from nested path 2`] = `"<li><d
exports[`general invalid command 1`] = `"<li><div id=\\"input-container\\" spellcheck=\\"false\\"><form><span data-testid=\\"input-prompt-path\\">/</span>&nbsp;<span id=\\"inputPrompt\\">$&gt;</span><input aria-label=\\"terminal-input\\" autocomplete=\\"none\\" autocapitalize=\\"none\\" autocorrect=\\"off\\" type=\\"text\\" readonly=\\"\\" value=\\"invalid-command\\"></form></div><span class=\\"commandResult\\">command not found: invalid-command</span></li>"`;
exports[`general invalid command 2`] = `"<li><div id=\\"input-container\\" spellcheck=\\"false\\"><form><span data-testid=\\"input-prompt-path\\">/</span>&nbsp;<span id=\\"inputPrompt\\">$&gt;</span><input aria-label=\\"terminal-input\\" autocomplete=\\"none\\" autocapitalize=\\"none\\" autocorrect=\\"off\\" type=\\"text\\" readonly=\\"\\" value=\\"invalid-command\\"></form></div><span class=\\"commandResult\\">command not found: invalid-command</span></li>"`;
exports[`help should print help menu 1`] = `"<li><div id=\\"input-container\\" spellcheck=\\"false\\"><form><span data-testid=\\"input-prompt-path\\">/</span>&nbsp;<span id=\\"inputPrompt\\">$&gt;</span><input aria-label=\\"terminal-input\\" autocomplete=\\"none\\" autocapitalize=\\"none\\" autocorrect=\\"off\\" type=\\"text\\" readonly=\\"\\" value=\\"help\\"></form></div><span class=\\"commandResult\\"><div id=\\"help-container\\"><ul aria-label=\\"help-menu\\"><li><span class=\\"help-command-name\\">cd</span> - <span>Changes the current working directory</span></li><li><span class=\\"help-command-name\\">pwd</span> - <span>Prints the current working directory</span></li><li><span class=\\"help-command-name\\">ls</span> - <span>Lists the contents of the given directory</span></li><li><span class=\\"help-command-name\\">mkdir</span> - <span>Creates a folder for a given path in the filesystem</span></li><li><span class=\\"help-command-name\\">cat</span> - <span>Shows the contents of a file</span></li><li><span class=\\"help-command-name\\">rm</span> - <span>Removes a file or directory</span></li><li><span class=\\"help-command-name\\">help</span> - <span>Prints list of available commands</span></li></ul></div></span></li>"`;
exports[`ls should correctly return contents for absolute path from nested path 1`] = `"<li><div id=\\"input-container\\" spellcheck=\\"false\\"><form><span data-testid=\\"input-prompt-path\\">/</span>&nbsp;<span id=\\"inputPrompt\\">$&gt;</span><input aria-label=\\"terminal-input\\" autocomplete=\\"none\\" autocapitalize=\\"none\\" autocorrect=\\"off\\" type=\\"text\\" readonly=\\"\\" value=\\"cd home\\"></form></div><span class=\\"commandResult\\"></span></li><li><div id=\\"input-container\\" spellcheck=\\"false\\"><form><span data-testid=\\"input-prompt-path\\">/home</span>&nbsp;<span id=\\"inputPrompt\\">$&gt;</span><input aria-label=\\"terminal-input\\" autocomplete=\\"none\\" autocapitalize=\\"none\\" autocorrect=\\"off\\" type=\\"text\\" readonly=\\"\\" value=\\"ls /home/user\\"></form></div><span class=\\"commandResult\\"><ul class=\\"terminal-ls-list\\"><li class=\\"ls-folder\\"> <span>test</span></li></ul></span></li>"`;
Expand Down
255 changes: 231 additions & 24 deletions src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ describe('general', (): void => {

expect(history.innerHTML).toMatchSnapshot();
});

test('invalid command', async (): Promise<void> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);
const input = getByLabelText('terminal-input');

fireEvent.change(input, { target: { value: 'invalid-command' } });
fireEvent.submit(input);

const history = await findByLabelText(container, 'terminal-history');

expect(history.innerHTML).toMatchSnapshot();
});
});

describe('autocomplete with tab', (): void => {
Expand All @@ -80,6 +94,142 @@ describe('autocomplete with tab', (): void => {
});
};

describe('general', (): void => {
test('tab without space for target should do nothing', async (): Promise<
void
> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);

const input = getByLabelText('terminal-input') as HTMLInputElement;
await userEvent.type(input, 'rm -r');
await fireTabInput(input);

const autoCompleteContent = await findByLabelText(
container,
'autocomplete-preview',
);

expect(autoCompleteContent.innerHTML).toBe('');
expect(input.value).toBe('rm -r');
});

test('should call "e.preventDefault" on tab key press', async (): Promise<
void
> => {
const { getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);
const input = getByLabelText('terminal-input') as HTMLInputElement;

const tabEvent = new KeyboardEvent('keydown', {
bubbles: true,
code: '9',
key: 'Tab',
});
Object.assign(tabEvent, { preventDefault: jest.fn() });

fireEvent(input, tabEvent);

await waitFor(() => {
expect(tabEvent.preventDefault).toHaveBeenCalledTimes(1);
});
});

test('should do nothing on tab with invalid command', async (): Promise<
void
> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);

const input = getByLabelText('terminal-input') as HTMLInputElement;

fireEvent.change(input, { target: { value: 'invalid ' } });
await fireTabInput(input);

const autoCompleteContent = await findByLabelText(
container,
'autocomplete-preview',
);

expect(autoCompleteContent.innerHTML).toBe('');
expect(input.value).toBe('invalid ');
});
});

describe('rm', (): void => {
test('rm tab with argument and relative nested path', async (): Promise<
void
> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);

const input = getByLabelText('terminal-input') as HTMLInputElement;
await userEvent.type(input, 'rm home/fi');
await fireTabInput(input);

const autoCompleteContent = await findByLabelText(
container,
'autocomplete-preview',
);

expect(autoCompleteContent.innerHTML).toContain('file1.txt');
expect(autoCompleteContent.innerHTML).toContain('file5.txt');
expect(autoCompleteContent.innerHTML).toMatchSnapshot();
expect(input.value).toBe('rm home/fi');
});

test('pressing tab with autocomplete menu visible should cycle through', async (): Promise<
void
> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);
const input = getByLabelText('terminal-input') as HTMLInputElement;
await userEvent.type(input, 'rm fi');
await fireTabInput(input);
await fireTabInput(input);

const autoCompleteContent = await findByLabelText(
container,
'autocomplete-preview',
);
expect(autoCompleteContent.innerHTML).toContain('file3.txt');
expect(autoCompleteContent.innerHTML).toContain('file4.txt');
expect(input.value).toBe('rm file3.txt');

await fireTabInput(input);
expect(input.value).toBe('rm file4.txt');

await fireTabInput(input);
expect(input.value).toBe('rm file3.txt');
});

test('rm tab with no target but command args', async (): Promise<void> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);

const input = getByLabelText('terminal-input') as HTMLInputElement;
await userEvent.type(input, 'rm -r ');
await fireTabInput(input);

const autoCompleteContent = await findByLabelText(
container,
'autocomplete-preview',
);

Object.keys(exampleFileSystem).forEach((item) => {
expect(autoCompleteContent.innerHTML).toContain(item);
});
expect(autoCompleteContent.innerHTML).toMatchSnapshot();
expect(input.value).toBe('rm -r ');
});
});

describe('ls', (): void => {
test('ls tab with no argument', async (): Promise<void> => {
const { container, getByLabelText } = render(
Expand Down Expand Up @@ -169,30 +319,6 @@ describe('autocomplete with tab', (): void => {
await fireTabInput(input);
expect(input.value).toBe('ls file3.txt');
});
});

describe('general', (): void => {
test('should call "e.preventDefault" on tab key press', async (): Promise<
void
> => {
const { getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);
const input = getByLabelText('terminal-input') as HTMLInputElement;

const tabEvent = new KeyboardEvent('keydown', {
bubbles: true,
code: '9',
key: 'Tab',
});
Object.assign(tabEvent, { preventDefault: jest.fn() });

fireEvent(input, tabEvent);

await waitFor(() => {
expect(tabEvent.preventDefault).toHaveBeenCalledTimes(1);
});
});

test('should clear preview display once command is executed', async (): Promise<
void
Expand Down Expand Up @@ -407,6 +533,69 @@ describe('autocomplete with tab', (): void => {
expect(autoCompleteContent.innerHTML).toBe('');
});
});

describe('cd', (): void => {
test('nested path with a single option', async (): Promise<void> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);

const input = getByLabelText('terminal-input') as HTMLInputElement;
await userEvent.type(input, 'cd home/user/');
await fireTabInput(input);

const autoCompleteContent = await findByLabelText(
container,
'autocomplete-preview',
);

expect(autoCompleteContent.innerHTML).toBe('');
expect(input.value).toEqual('cd home/user/test/');
});
test('tab press with single item should autofill it', async (): Promise<
void
> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);
const input = getByLabelText('terminal-input') as HTMLInputElement;
await userEvent.type(input, 'cd ho');
await fireTabInput(input);

const autoCompleteContent = await findByLabelText(
container,
'autocomplete-preview',
);
expect(input.value).toBe('cd home/');
expect(autoCompleteContent.innerHTML).toBe('');
});

test('multiple tab presses with changing targets', async (): Promise<
void
> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);
const input = getByLabelText('terminal-input') as HTMLInputElement;
await userEvent.type(input, 'cd ');
await fireTabInput(input);
await fireTabInput(input);

const autoCompleteContent = await findByLabelText(
container,
'autocomplete-preview',
);
expect(autoCompleteContent.innerHTML).toContain('home/');
expect(autoCompleteContent.innerHTML).toContain('docs');
expect(input.value).toBe('cd home/');

input.value = '';
await userEvent.type(input, 'cd do');
await fireTabInput(input);

expect(input.value).toBe('cd docs/');
});
});
});

describe('cd', (): void => {
Expand Down Expand Up @@ -731,6 +920,24 @@ describe('mkdir', (): void => {
});
});

describe('cat', (): void => {
test('should handle cat with no space', async (): Promise<void> => {
const { container, getByLabelText } = render(
<Terminal fileSystem={exampleFileSystem} />,
);

const input = getByLabelText('terminal-input');

fireEvent.change(input, { target: { value: 'cat' } });
fireEvent.submit(input);

const history = await findByLabelText(container, 'terminal-history');

expect(history.innerHTML).toContain('Error: Invalid target path');
expect(history.innerHTML).toMatchSnapshot();
});
});

describe('rm', (): void => {
test('should remove file from root', async (): Promise<void> => {
const { container, getByLabelText } = render(
Expand Down
2 changes: 1 addition & 1 deletion src/commands/__tests__/__snapshots__/mkdir.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`mkdir suite Failure should reject if path already exists 1`] = `"Path already exists"`;
exports[`mkdir suite failure should reject if path already exists 1`] = `"Path already exists"`;
Loading

0 comments on commit 621fb82

Please sign in to comment.