Skip to content

Commit 0f5fa20

Browse files
Merge pull request #20 from oslabs-beta/dev
Dev to main
2 parents e9e6fe4 + c2a7d5c commit 0f5fa20

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1589
-32
lines changed

.babelrc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"presets": ["@babel/preset-env",
3+
[
4+
"@babel/preset-react",
5+
{
6+
"runtime":"automatic"
7+
}
8+
],
9+
"@babel/preset-typescript"
10+
]
11+
// "plugins": [
12+
// ["transform-runtime", {
13+
// "regenerator": true
14+
// }]
15+
// ]
16+
}

.eslintrc.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"es2021": true
5+
},
6+
"extends": [
7+
"eslint:recommended",
8+
"plugin:react/recommended",
9+
"plugin:@typescript-eslint/recommended"
10+
],
11+
"parser": "@typescript-eslint/parser",
12+
"parserOptions": {
13+
"ecmaFeatures": {
14+
"jsx": true
15+
},
16+
"ecmaVersion": "latest",
17+
"sourceType": "module"
18+
},
19+
"plugins": [
20+
"react",
21+
"@typescript-eslint"
22+
],
23+
"rules": {
24+
}
25+
}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
dist/
3+
package-lock.json
4+
.DS_Store

README.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,50 @@
1-
# obsidian-developer-tool
1+
# Obsidian-Developer-Tool
2+
3+
The Obsidian Developer Tool is an easy-to-use chrome developer tool extension designed for applications using Obsidian. With this extension, users can:
4+
5+
- visualize GraphQL query and cache performance metrics
6+
- send dynamic queries and mutations to a user's database
7+
- view and evict data from the browser cache
8+
9+
These features require minimal configuration and are designed to cater to the needs of Obsidian developers utilizing Obsidian Wrapper in their applications.
10+
11+
The Obsidian Developer Tool is an open-source developer tool accelerated by OS Labs and developed by [Yurii Shchyrba](https://github.com/YuriiShchyrba), [Linda Zhao](https://github.com/lzhao15), [Ali Fay](https://github.com/ali-fay), [Anthony Guan](https://github.com/guananthony), [Yasir Choudhury](https://github.com/Yasir-Choudhury)
12+
13+
# Installation
14+
15+
The Obsidian Developer Tool is currently under the review process to be launched on the Chrome Extension Store. In the meantime, the easiest way to use the developer tool is to build from source and manually add as a chrome extension. To build the latest version, execute the following commands:
16+
17+
18+
```
19+
git clone https://github.com/oslabs-beta/obsidian-developer-tool
20+
npm install
21+
npm run build
22+
```
23+
24+
Then, in the Chrome Extensions Page (chrome://extensions/), toggle "Developer mode" on in the upper righthand corner, click on "Load unpacked" and navigate to /Obsidian-developer-tool/dist/ and click "Select". The extension should now be loaded and available within chrome developer tools.
25+
26+
# Usage and Configuration
27+
Clone the Obsidian repository [here](https://github.com/open-source-labs/obsidian), and in the Obsidian Wrapper file, on line 10, update ```chromeExtensionId``` to the value of the unique chrome extension ID for the tool you just unpacked in your extensions. This can be found at chrome://extensions/ on the card for your loaded extension.
28+
29+
There is no further configuration necessary. As long as your application is using Obsidian Wrapper (imported as a path to the local file with the updated chrome extension), the devtool will be able to retrieve cache data and query metrics on actions initiated in the app.
30+
31+
**Performance:** <br/>
32+
Navigate to this tab if you would like to visualize the response time of your GraphQL queries. You can access a log of your queries and mutations, as well as the corresponding response time data. Here you can see the lower response times on subsequent queries for the same data - Obsidian's caching strategies at work!
33+
34+
**Cache:** <br/>
35+
Navigate to this tab to see the data currently in your client-side cache based on queries being made. All of the cached data will appear here, and you also have the ability to manually clear the cache with the 'clear cache' button.
36+
37+
**Playground:** <br/>
38+
In order to use this feature, you must plug in your server's GraphQL endpoint (ex. http://localhost:3000/graphQL) and click the submit button. You will now be able to write queries as well as mutations in order to retrieve and view your data.
39+
40+
**Usage Note:**
41+
Use of this developer tool requires Obsidian version 5.0 or greater.
42+
43+
<div><img src='./src/assets/gifs/performance.gif' width="60%"></div>
44+
<div><img src='./src/assets/gifs/cache.gif' width="60%"></div>
45+
<div><img src='./src/assets/gifs/playground.gif' width="60%"></div>
46+
47+
# More information:
48+
Obsidian and Obsidian demo documentation:
49+
* [Obsidian](https://github.com/open-source-labs/obsidian)
50+
* [Obsidian Demo](https://github.com/oslabs-beta/obsidian-demo-5.0)

__test__/cache.js

Whitespace-only changes.

__test__/performance.js

Whitespace-only changes.

__test__/playground.test.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { useInput } from '../src/pages/Panel/Components/useInput';
2+
import Enzyme , {mount,shallow} from 'enzyme';
3+
import { act, renderHook } from '@testing-library/react-hooks';
4+
import Playground from '../src/pages/Panel/Components/Playground';
5+
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
6+
import PlaygroundHeader from '../src/pages/Panel/Components/PlaygroundHeader';
7+
import QueryInput from '../src/pages/Panel/Components/QueryInput';
8+
import QueryOutput from '../src/pages/Panel/Components/QueryOutput';
9+
10+
11+
Enzyme.configure({ adapter: new Adapter() });
12+
13+
describe('Input Insertion', () => {
14+
15+
let wrapper;
16+
17+
it('renders children',()=>{
18+
wrapper = shallow(<Playground />);
19+
expect(wrapper.containsMatchingElement(<PlaygroundHeader />)).toEqual(true);
20+
expect(wrapper.containsMatchingElement(<QueryInput />)).toEqual(true);
21+
expect(wrapper.containsMatchingElement(<QueryOutput />)).toEqual(true);
22+
});
23+
24+
it('send "simple text" input value', () => {
25+
const { result } = renderHook(useInput);
26+
27+
act(() => {
28+
result.current.onChange('simple text');
29+
});
30+
31+
expect(result.current.inputValue).toBe('simple text');
32+
});
33+
34+
it('send "" (no input) input value', () => {
35+
const { result } = renderHook(useInput);
36+
37+
act(() => {
38+
result.current.onChange('');
39+
});
40+
41+
expect(result.current.inputValue).toBe('');
42+
});
43+
});

__test__/react.test.js

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import React from 'React';
2+
import userEvent from '@testing-library/user-event';
3+
import { render, screen, waitFor } from '@testing-library/react';
4+
import regeneratorRuntime from 'regenerator-runtime';
5+
6+
import Header from '../src/pages/Panel/Components/AppBar.tsx';
7+
import Queries from '../src/pages/Panel/Components/Performance Components/Queries.tsx';
8+
import Log from '../src/pages/Panel/Components/Performance Components/Log.tsx';
9+
10+
import Playground from '../src/pages/Panel/Components/Playground';
11+
import PlaygroundHeader from '../src/pages/Panel/Components/PlaygroundHeader';
12+
13+
document.createRange = () => {
14+
const range = new Range();
15+
16+
range.getBoundingClientRect = jest.fn();
17+
18+
range.getClientRects = () => {
19+
return {
20+
item: () => null,
21+
length: 0,
22+
[Symbol.iterator]: jest.fn()
23+
};
24+
};
25+
26+
return range;
27+
}
28+
29+
describe('Unit testing React components', () => {
30+
describe('Side Bar', () => {
31+
test('Header is mounted', () => {
32+
const props = {
33+
count: 1,
34+
setCount: jest.fn()
35+
}
36+
render (<Header {...props}/>)
37+
const header = screen.getAllByText('Obsidian Developer Tool')
38+
expect(header.length === 1)
39+
})
40+
});
41+
42+
describe('Performance Tab', () => {
43+
//check amount of queries and mutation
44+
test('Number of query log components responds to number of query messages', () => {
45+
const props = {
46+
data: ['beans', 2, 3],
47+
setGraphqlData: jest.fn(),
48+
};
49+
const test = render(<Queries {...props} />);
50+
const logs0 = screen.getAllByText('0. Query');
51+
expect(logs0.length).toBe(1);
52+
const logs1 = screen.getAllByText('1. Query');
53+
expect(logs1.length).toBe(1);
54+
const logs2 = screen.getAllByText('2. Query');
55+
expect(logs2.length).toBe(1);
56+
});
57+
//check to see if graphql click event listener is activated
58+
test('Log functions invoked on click', () => {
59+
const props = {
60+
onClick: jest.fn(),
61+
name: 'test',
62+
};
63+
render(<Log {...props} />);
64+
const logs = screen.getByText(props.name);
65+
userEvent.click(logs);
66+
expect(props.onClick).toHaveBeenCalledTimes(1);
67+
userEvent.click(logs);
68+
expect(props.onClick).toHaveBeenCalledTimes(2);
69+
});
70+
});
71+
72+
describe('Playground Tab', () => {
73+
74+
test('Playground input field', ()=>{
75+
render(<Playground />)
76+
userEvent.type((screen.getByText('Submit')).previousSibling, 'http://localhost:8000/graphql');
77+
userEvent.click(screen.getByText('Submit'));
78+
expect(screen.getByRole('heading').textContent).toBe('Current Endpoint: http://localhost:8000/graphql');
79+
});
80+
81+
test('Playground security test for harmful characters', ()=>{
82+
render(<Playground />)
83+
userEvent.type((screen.getByText('Submit')).previousSibling, 'harmful characters " ) & < ');
84+
userEvent.click(screen.getByText('Submit'));
85+
expect(screen.getByRole('heading').textContent).toBe("Current Endpoint: harmful characters &amp;amp;amp;amp;amp;amp;amp;quot; &amp;amp;amp;amp;amp;parens; &amp;amp;amp;amp; &amp;lt; ");
86+
});
87+
88+
89+
test('Endpoint submit button invokes function on click', () => {
90+
const props = {
91+
onEndpointChange: jest.fn()
92+
};
93+
render(<PlaygroundHeader {...props} />)
94+
const button = screen.getByRole('button')
95+
userEvent.click(button);
96+
expect(props.onEndpointChange).toHaveBeenCalledTimes(1);
97+
userEvent.click(button);
98+
expect(props.onEndpointChange).toHaveBeenCalledTimes(2);
99+
});
100+
101+
test('Input value initially set to empty string with placeholder', () => {
102+
const props = {
103+
onEndpointChange: jest.fn()
104+
};
105+
render(<PlaygroundHeader {...props} />)
106+
const input = screen.getAllByDisplayValue('')
107+
expect(input.length).toBe(1)
108+
expect(input[0].getAttribute('placeholder')).toBe('Enter GraphQL endpoint here')
109+
});
110+
111+
test('Input value changes with typing', () => {
112+
const props = {
113+
onEndpointChange: jest.fn()
114+
};
115+
render(<PlaygroundHeader {...props} />)
116+
const input = screen.getByDisplayValue('')
117+
userEvent.type(input, 'hello')
118+
const newInput = screen.getAllByDisplayValue('hello')
119+
expect(newInput.length).toBe(1)
120+
});
121+
122+
test('Input value resets after button click', () => {
123+
const props = {
124+
onEndpointChange: jest.fn()
125+
};
126+
render(<PlaygroundHeader {...props} />)
127+
const input = screen.getAllByDisplayValue('')
128+
expect(input.length).toBe(1)
129+
130+
userEvent.type(screen.getByDisplayValue(''), 'hello')
131+
const testInput = screen.queryAllByDisplayValue('')
132+
expect(testInput.length).toBe(0)
133+
const newInput = screen.getAllByDisplayValue('hello')
134+
expect(newInput.length).toBe(1)
135+
const button = screen.getByRole('button')
136+
userEvent.click(button);
137+
const clickInput = screen.getAllByDisplayValue('')
138+
expect(clickInput.length).toBe(1)
139+
const oldInput = screen.queryAllByDisplayValue('hello')
140+
expect(oldInput.length).toBe(0)
141+
});
142+
});
143+
});

babel.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
presets: [
3+
['@babel/preset-env', {targets: {node: 'current'}}],
4+
'@babel/preset-typescript',
5+
],
6+
};

devtools.html

Lines changed: 0 additions & 16 deletions
This file was deleted.

manifest.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)