@laboratoria/sdk-js 0.0.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/node.js.yml +31 -0
- package/README.md +40 -3
- package/index.js +12 -20
- package/index.spec.js +12 -12
- package/lib/core.js +113 -12
- package/lib/curriculum.js +59 -0
- package/lib/curriculum.spec.js +194 -0
- package/lib/jobs.js +21 -3
- package/lib/model.js +86 -35
- package/lib/model.spec.js +28 -1
- package/package.json +20 -10
- package/schemas/core.json +217 -12
- package/__mocks__/firebase/app.js +0 -1
- package/__mocks__/firebase/auth.js +0 -10
- package/__snapshots__/index.spec.js.snap +0 -12
- package/lib/__mocks__/client.js +0 -1
- package/lib/campuses.js +0 -23
- package/lib/team.js +0 -50
- package/schemas/team.json +0 -126
@@ -0,0 +1,31 @@
|
|
1
|
+
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
2
|
+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
3
|
+
|
4
|
+
name: Node.js CI
|
5
|
+
|
6
|
+
on:
|
7
|
+
push:
|
8
|
+
branches: [ main ]
|
9
|
+
pull_request:
|
10
|
+
branches: [ main ]
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
build:
|
14
|
+
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
|
17
|
+
strategy:
|
18
|
+
matrix:
|
19
|
+
node-version: [14.x, 16.x]
|
20
|
+
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
21
|
+
|
22
|
+
steps:
|
23
|
+
- uses: actions/checkout@v2
|
24
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
25
|
+
uses: actions/setup-node@v2
|
26
|
+
with:
|
27
|
+
node-version: ${{ matrix.node-version }}
|
28
|
+
cache: 'npm'
|
29
|
+
- run: npm ci
|
30
|
+
- run: npm run build --if-present
|
31
|
+
- run: npm test
|
package/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
## Laboratoria JavaScript (browser) SDK
|
2
2
|
|
3
|
+
[](https://github.com/Laboratoria/sdk-js/actions/workflows/node.js.yml)
|
4
|
+
|
3
5
|
:warning: This tool is still in draft stage and is likely to change without
|
4
6
|
notice.
|
5
7
|
|
@@ -25,7 +27,6 @@ const app = createApp({
|
|
25
27
|
firebaseApiKey: '',
|
26
28
|
firebaseProject: '',
|
27
29
|
coreApiUrl: '',
|
28
|
-
teamApiUrl: '',
|
29
30
|
jobsApiUrl: '',
|
30
31
|
});
|
31
32
|
```
|
@@ -79,7 +80,6 @@ app.user.create({
|
|
79
80
|
### Cohorts
|
80
81
|
|
81
82
|
```js
|
82
|
-
// Cohorts API
|
83
83
|
app.cohort.findMany({
|
84
84
|
where: {
|
85
85
|
end: { gt: new Date() },
|
@@ -96,13 +96,50 @@ app.cohort.findMany({
|
|
96
96
|
|
97
97
|
### Students
|
98
98
|
|
99
|
+
WIP
|
100
|
+
|
99
101
|
### Dropouts
|
100
102
|
|
103
|
+
WIP
|
101
104
|
|
102
105
|
### Projects
|
103
106
|
|
104
107
|
```js
|
105
108
|
app.project.findMany();
|
106
109
|
|
107
|
-
|
110
|
+
app.project.findMany({ tag: 'v3.0.0' });
|
111
|
+
|
112
|
+
app.project.findMany({
|
113
|
+
locale: 'es-ES',
|
114
|
+
track: 'js',
|
115
|
+
});
|
116
|
+
|
117
|
+
app.project.findById('cipher');
|
118
|
+
|
119
|
+
app.project.findById('cipher', { tag: 'v3.0.0' });
|
108
120
|
```
|
121
|
+
|
122
|
+
### Topics
|
123
|
+
|
124
|
+
```js
|
125
|
+
app.topic.findMany();
|
126
|
+
|
127
|
+
app.topic.findMany({ tag: 'v3.0.0' });
|
128
|
+
|
129
|
+
app.topic.findMany({
|
130
|
+
locale: 'es-ES',
|
131
|
+
track: 'js',
|
132
|
+
});
|
133
|
+
|
134
|
+
app.topic.findById('javascript');
|
135
|
+
|
136
|
+
app.topic.findById('javascript', { tag: 'v3.0.0' });
|
137
|
+
```
|
138
|
+
|
139
|
+
### Learning Objectives
|
140
|
+
|
141
|
+
```js
|
142
|
+
app.learningObjective.findMany();
|
143
|
+
|
144
|
+
app.learningObjective.findMany({ tag: 'v3.0.0' });
|
145
|
+
```
|
package/index.js
CHANGED
@@ -5,16 +5,14 @@ import {
|
|
5
5
|
signInWithEmailAndPassword,
|
6
6
|
signOut,
|
7
7
|
} from 'firebase/auth';
|
8
|
-
import { createClient } from './lib/client';
|
9
8
|
import { createAPI as createCoreAPI } from './lib/core';
|
9
|
+
import { createAPI as createCurriculumAPI } from './lib/curriculum';
|
10
10
|
import { createAPI as createJobsAPI } from './lib/jobs';
|
11
|
-
import { createAPI as createTeamAPI } from './lib/team';
|
12
11
|
|
13
12
|
export const createApp = ({
|
14
13
|
firebaseApiKey = 'AIzaSyAXbaEbpq8NOfn0r8mIrcoHvoGRkJThwdc',
|
15
14
|
firebaseProject = 'laboratoria-la',
|
16
15
|
coreApiUrl = 'https://us-central1-outpost-272720.cloudfunctions.net/core-api',
|
17
|
-
teamApiUrl = 'https://us-central1-outpost-272720.cloudfunctions.net/team-api',
|
18
16
|
jobsApiUrl = 'https://us-central1-outpost-272720.cloudfunctions.net/jobs-api',
|
19
17
|
} = {}) => {
|
20
18
|
const firebaseApp = initializeApp({
|
@@ -26,31 +24,25 @@ export const createApp = ({
|
|
26
24
|
|
27
25
|
const firebaseAuth = getAuth(firebaseApp);
|
28
26
|
const state = { authUser: undefined, user: undefined };
|
29
|
-
|
30
|
-
const
|
31
|
-
|
32
|
-
};
|
27
|
+
const coreAPI = createCoreAPI(coreApiUrl, state);
|
28
|
+
const jobsAPI = createJobsAPI(jobsApiUrl, state);
|
29
|
+
const curriculumAPI = createCurriculumAPI();
|
33
30
|
|
34
31
|
const authAPI = {
|
35
32
|
onChange: fn => onAuthStateChanged(firebaseAuth, (authUser) => {
|
36
33
|
if (!authUser) {
|
37
|
-
|
34
|
+
Object.assign(state, { authUser: null, user: null });
|
38
35
|
return fn(state);
|
39
36
|
}
|
40
|
-
|
37
|
+
Object.assign(state, { authUser });
|
38
|
+
coreAPI.user.findById(authUser.uid)
|
41
39
|
.then((user) => {
|
42
|
-
Object.assign(
|
43
|
-
isStaff: ['staff', 'manager', 'finance', 'admin'].includes(user.role),
|
44
|
-
isManager: ['manager', 'finance', 'admin'].includes(user.role),
|
45
|
-
isFinance: ['finance', 'admin'].includes(user.role),
|
46
|
-
isAdmin: user.role === 'admin',
|
47
|
-
});
|
48
|
-
setState(authUser, user);
|
40
|
+
Object.assign(state, { user });
|
49
41
|
fn(state);
|
50
42
|
})
|
51
43
|
.catch((err) => {
|
52
44
|
console.error(err);
|
53
|
-
|
45
|
+
Object.assign(state, { authUser: null, user: null });
|
54
46
|
fn(state);
|
55
47
|
});
|
56
48
|
}),
|
@@ -63,9 +55,9 @@ export const createApp = ({
|
|
63
55
|
};
|
64
56
|
|
65
57
|
return {
|
58
|
+
...jobsAPI,
|
59
|
+
...curriculumAPI,
|
60
|
+
...coreAPI,
|
66
61
|
auth: authAPI,
|
67
|
-
...createCoreAPI(coreApiUrl, state),
|
68
|
-
...createJobsAPI(jobsApiUrl, state),
|
69
|
-
...createTeamAPI(teamApiUrl, state),
|
70
62
|
};
|
71
63
|
};
|
package/index.spec.js
CHANGED
@@ -5,10 +5,16 @@ import {
|
|
5
5
|
signInWithEmailAndPassword,
|
6
6
|
signOut,
|
7
7
|
} from 'firebase/auth';
|
8
|
-
import {
|
8
|
+
import { createAPI as createCoreAPI } from './lib/core';
|
9
9
|
import { createApp } from './index.js';
|
10
10
|
|
11
|
-
jest.mock('./lib/
|
11
|
+
jest.mock('./lib/core.js', () => ({
|
12
|
+
createAPI: jest.fn().mockReturnValue({
|
13
|
+
user: {
|
14
|
+
findById: jest.fn().mockResolvedValue({}),
|
15
|
+
},
|
16
|
+
}),
|
17
|
+
}));
|
12
18
|
|
13
19
|
beforeEach(() => {
|
14
20
|
initializeApp.mockClear();
|
@@ -40,7 +46,7 @@ describe('app.auth.onChange', () => {
|
|
40
46
|
});
|
41
47
|
});
|
42
48
|
|
43
|
-
it('should fetch user from db when authenticated
|
49
|
+
it('should fetch user from db when authenticated using coreAPI', (done) => {
|
44
50
|
const { auth } = createApp();
|
45
51
|
const mockAuthUser = { uid: 'xxx', getIdToken: () => 'token' };
|
46
52
|
const userMock = { uid: 'xxx', email: 'foo@bar.baz' };
|
@@ -50,17 +56,11 @@ describe('app.auth.onChange', () => {
|
|
50
56
|
return () => { };
|
51
57
|
});
|
52
58
|
|
53
|
-
|
59
|
+
createCoreAPI().user.findById.mockResolvedValue(userMock);
|
54
60
|
|
55
61
|
auth.onChange(({ authUser, user }) => {
|
56
62
|
expect(authUser).toEqual(mockAuthUser);
|
57
|
-
expect(user).toEqual(
|
58
|
-
...userMock,
|
59
|
-
isStaff: false,
|
60
|
-
isManager: false,
|
61
|
-
isFinance: false,
|
62
|
-
isAdmin: false,
|
63
|
-
});
|
63
|
+
expect(user).toEqual(userMock);
|
64
64
|
done();
|
65
65
|
});
|
66
66
|
});
|
@@ -76,7 +76,7 @@ describe('app.auth.onChange', () => {
|
|
76
76
|
return () => { };
|
77
77
|
});
|
78
78
|
|
79
|
-
|
79
|
+
createCoreAPI().user.findById.mockRejectedValueOnce(error);
|
80
80
|
|
81
81
|
auth.onChange(({ authUser, user }) => {
|
82
82
|
expect(authUser).toBeNull();
|
package/lib/core.js
CHANGED
@@ -1,14 +1,20 @@
|
|
1
|
+
import md5 from 'blueimp-md5';
|
2
|
+
import currencies from './currencies';
|
3
|
+
import roles from './roles';
|
1
4
|
import { createModels, extendSchemaDefinitions } from './model';
|
2
5
|
import schema from '../schemas/core.json';
|
3
6
|
|
4
7
|
const extended = {
|
8
|
+
Country: {
|
9
|
+
plural: 'countries',
|
10
|
+
},
|
5
11
|
User: {
|
6
12
|
primaryKey: 'uid',
|
7
13
|
inputProps: [
|
8
14
|
'firstName',
|
9
15
|
'lastName',
|
10
16
|
'email',
|
11
|
-
'
|
17
|
+
'lang',
|
12
18
|
'github',
|
13
19
|
'linkedin',
|
14
20
|
'bio',
|
@@ -16,17 +22,41 @@ const extended = {
|
|
16
22
|
'signupCohort',
|
17
23
|
'disabled',
|
18
24
|
],
|
25
|
+
searchProps: ['firstName', 'lastName', 'email'],
|
26
|
+
getOptionLabel: ({ firstName, lastName, email }) => `${firstName} ${lastName} (${email})`,
|
19
27
|
properties: {
|
20
28
|
email: {
|
21
29
|
inputType: 'email',
|
22
30
|
},
|
23
|
-
locale: {
|
24
|
-
enum: ['es-ES', 'pt-BR'],
|
25
|
-
},
|
26
31
|
bio: {
|
27
32
|
inputType: 'textarea',
|
28
33
|
},
|
29
34
|
},
|
35
|
+
parse: (props) => {
|
36
|
+
const avatar = (
|
37
|
+
props.github
|
38
|
+
? `https://github.com/${props.github}.png?size=`
|
39
|
+
: `https://www.gravatar.com/avatar/${md5(props.email)}?s=`
|
40
|
+
)
|
41
|
+
return {
|
42
|
+
...props,
|
43
|
+
fullName: `${props.firstName} ${props.lastName}`,
|
44
|
+
avatar: size => `${avatar}${size}`,
|
45
|
+
isStaff: ['staff', 'manager', 'finance', 'admin'].includes(props.role),
|
46
|
+
isManager: ['manager', 'finance', 'admin'].includes(props.role),
|
47
|
+
isFinance: ['finance', 'admin'].includes(props.role),
|
48
|
+
isAdmin: props.role === 'admin',
|
49
|
+
};
|
50
|
+
},
|
51
|
+
},
|
52
|
+
Track: {
|
53
|
+
searchProps: ['name'],
|
54
|
+
},
|
55
|
+
Program: {
|
56
|
+
searchProps: ['name'],
|
57
|
+
},
|
58
|
+
Stage: {
|
59
|
+
searchProps: ['name'],
|
30
60
|
},
|
31
61
|
Cohort: {
|
32
62
|
inputProps: [
|
@@ -37,13 +67,37 @@ const extended = {
|
|
37
67
|
'end',
|
38
68
|
'legacySlug',
|
39
69
|
],
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
70
|
+
searchProps: ['name'],
|
71
|
+
getOptionLabel: ({ id, name, stage }) => (
|
72
|
+
`${name}${!stage ? '' : ` - ${stage.name}`} (id: ${id})`
|
73
|
+
),
|
74
|
+
properties: {},
|
75
|
+
parse: (props) => {
|
76
|
+
const now = Date.now();
|
77
|
+
// TODO: Handle case where start and/or end have not been selected in query
|
78
|
+
const status = (
|
79
|
+
props.start > now
|
80
|
+
? 'upcoming'
|
81
|
+
: props.end < now
|
82
|
+
? 'past'
|
83
|
+
: 'active'
|
84
|
+
);
|
85
|
+
const size = (
|
86
|
+
status === 'upcoming' && props.vacancies
|
87
|
+
? props.vacancies
|
88
|
+
: props._count?.students || props.students?.length || 0
|
89
|
+
);
|
90
|
+
return {
|
91
|
+
...props,
|
92
|
+
status,
|
93
|
+
size,
|
94
|
+
};
|
44
95
|
},
|
45
96
|
},
|
46
|
-
Student: {
|
97
|
+
Student: {
|
98
|
+
inputProps: [],
|
99
|
+
searchProps: [],
|
100
|
+
},
|
47
101
|
Dropout: {
|
48
102
|
inputProps: [
|
49
103
|
'cohort',
|
@@ -51,12 +105,56 @@ const extended = {
|
|
51
105
|
'date',
|
52
106
|
'reason',
|
53
107
|
'reasonDetail',
|
54
|
-
'
|
55
|
-
'
|
108
|
+
'lastProject',
|
109
|
+
'completedProjects',
|
56
110
|
'notes',
|
57
111
|
'staffSad',
|
58
112
|
'covidRelated',
|
59
113
|
],
|
114
|
+
searchProps: [
|
115
|
+
'user.uid',
|
116
|
+
'user.firstName',
|
117
|
+
'user.lastName',
|
118
|
+
'user.email',
|
119
|
+
'cohort.name',
|
120
|
+
],
|
121
|
+
},
|
122
|
+
Contract: {
|
123
|
+
inputProps: [
|
124
|
+
'user',
|
125
|
+
'countryCode',
|
126
|
+
'currency',
|
127
|
+
'isEmployment',
|
128
|
+
'feeBasis',
|
129
|
+
'feeAmount',
|
130
|
+
'hoursPerWeek',
|
131
|
+
'start',
|
132
|
+
'end',
|
133
|
+
],
|
134
|
+
properties: {
|
135
|
+
countryCode: {
|
136
|
+
enum: ['BR', 'CL', 'CO', 'MX', 'PE'],
|
137
|
+
},
|
138
|
+
currency: {
|
139
|
+
enum: currencies,
|
140
|
+
},
|
141
|
+
},
|
142
|
+
},
|
143
|
+
Gig: {
|
144
|
+
inputProps: [
|
145
|
+
// 'contract',
|
146
|
+
'cohort',
|
147
|
+
'user',
|
148
|
+
'role',
|
149
|
+
'hoursPerWeek',
|
150
|
+
'start',
|
151
|
+
'end',
|
152
|
+
],
|
153
|
+
properties: {
|
154
|
+
role: {
|
155
|
+
enum: roles,
|
156
|
+
},
|
157
|
+
},
|
60
158
|
},
|
61
159
|
};
|
62
160
|
|
@@ -65,4 +163,7 @@ export const createAPI = (url, state) => createModels(url, state, {
|
|
65
163
|
definitions: extendSchemaDefinitions(schema, extended),
|
66
164
|
});
|
67
165
|
|
68
|
-
// const {
|
166
|
+
// const {
|
167
|
+
// delete: _,
|
168
|
+
// ...userAPI,
|
169
|
+
// } = createModel(coreApiUrl, state, 'users', schemas.user);
|
@@ -0,0 +1,59 @@
|
|
1
|
+
const releasesUrl = 'https://api.github.com/repos/Laboratoria/bootcamp/releases';
|
2
|
+
const rawUrl = 'https://raw.githubusercontent.com/Laboratoria/bootcamp';
|
3
|
+
|
4
|
+
const getLatestVersion = () => fetch(`${releasesUrl}/latest`)
|
5
|
+
.then(resp => resp.json())
|
6
|
+
.then(({ tag_name }) => tag_name);
|
7
|
+
|
8
|
+
const fetchProjects = async tag => (
|
9
|
+
fetch(`${rawUrl}/${tag || await getLatestVersion()}/dist/projects.json`)
|
10
|
+
.then(resp => resp.json())
|
11
|
+
);
|
12
|
+
|
13
|
+
const fetchProject = async (slug, tag) => (
|
14
|
+
fetch(`${rawUrl}/${tag || await getLatestVersion()}/dist/projects/${slug}.json`)
|
15
|
+
.then(resp => resp.json())
|
16
|
+
);
|
17
|
+
|
18
|
+
const fetchTopics = async tag => (
|
19
|
+
fetch(`${rawUrl}/${tag || await getLatestVersion()}/dist/topics.json`)
|
20
|
+
.then(resp => resp.json())
|
21
|
+
);
|
22
|
+
|
23
|
+
const fetchTopic = async (slug, tag) => (
|
24
|
+
fetch(`${rawUrl}/${tag || await getLatestVersion()}/dist/topics/${slug}.json`)
|
25
|
+
.then(resp => resp.json())
|
26
|
+
);
|
27
|
+
|
28
|
+
const fetchLearningObjectives = async tag => (
|
29
|
+
fetch(`${rawUrl}/${tag || await getLatestVersion()}/dist/learning-objectives.json`)
|
30
|
+
.then(resp => resp.json())
|
31
|
+
);
|
32
|
+
|
33
|
+
const filterByLocaleAndTrack = opts => arr => arr.filter((obj) => {
|
34
|
+
if (opts.locale && opts.locale !== obj.locale) {
|
35
|
+
return false;
|
36
|
+
}
|
37
|
+
if (opts.track && opts.track !== obj.track) {
|
38
|
+
return false;
|
39
|
+
}
|
40
|
+
return true;
|
41
|
+
});
|
42
|
+
|
43
|
+
export const createAPI = () => {
|
44
|
+
return {
|
45
|
+
projects: {
|
46
|
+
findMany: (opts = {}) => fetchProjects(opts.tag)
|
47
|
+
.then(filterByLocaleAndTrack(opts)),
|
48
|
+
findById: (slug, opts = {}) => fetchProject(slug, opts.tag),
|
49
|
+
},
|
50
|
+
topics: {
|
51
|
+
findMany: (opts = {}) => fetchTopics(opts.tag)
|
52
|
+
.then(filterByLocaleAndTrack(opts)),
|
53
|
+
findById: (slug, opts = {}) => fetchTopic(slug, opts.tag),
|
54
|
+
},
|
55
|
+
learningObjectives: {
|
56
|
+
findMany: (opts = {}) => fetchLearningObjectives(opts.tag),
|
57
|
+
},
|
58
|
+
};
|
59
|
+
};
|
@@ -0,0 +1,194 @@
|
|
1
|
+
import { createAPI } from './curriculum';
|
2
|
+
|
3
|
+
describe('projects', () => {
|
4
|
+
describe('findMany', () => {
|
5
|
+
// TODO: errores HTTP, GitHub caido, repo borrado, etc...
|
6
|
+
|
7
|
+
it('sends request to get latest version and then corresponding json', () => {
|
8
|
+
global.fetch = jest.fn().mockImplementation(async url => ({
|
9
|
+
status: 200,
|
10
|
+
json: jest.fn().mockResolvedValue(
|
11
|
+
url.startsWith('https://api.')
|
12
|
+
? { tag_name: 'v4.0.0' }
|
13
|
+
: []
|
14
|
+
),
|
15
|
+
}));
|
16
|
+
|
17
|
+
return createAPI().projects.findMany()
|
18
|
+
.then((projects) => {
|
19
|
+
expect(projects).toEqual([]);
|
20
|
+
expect(global.fetch).toHaveBeenCalledTimes(2);
|
21
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
22
|
+
1,
|
23
|
+
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
24
|
+
);
|
25
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
26
|
+
2,
|
27
|
+
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/projects.json',
|
28
|
+
);
|
29
|
+
});
|
30
|
+
});
|
31
|
+
|
32
|
+
it('gets projects in specific tag when passed as option', () => {
|
33
|
+
global.fetch = jest.fn().mockImplementation(async url => ({
|
34
|
+
status: 200,
|
35
|
+
json: jest.fn().mockResolvedValue(
|
36
|
+
url.startsWith('https://api.')
|
37
|
+
? { tag_name: 'v4.0.0' }
|
38
|
+
: []
|
39
|
+
),
|
40
|
+
}));
|
41
|
+
|
42
|
+
return createAPI().projects.findMany({ tag: 'v3.0.0' })
|
43
|
+
.then((projects) => {
|
44
|
+
expect(projects).toEqual([]);
|
45
|
+
expect(global.fetch).toHaveBeenCalledTimes(1);
|
46
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
47
|
+
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v3.0.0/dist/projects.json',
|
48
|
+
);
|
49
|
+
});
|
50
|
+
});
|
51
|
+
|
52
|
+
it('gets projects in specific tag when passed as option', () => {
|
53
|
+
global.fetch = jest.fn().mockImplementation(async url => ({
|
54
|
+
status: 200,
|
55
|
+
json: jest.fn().mockResolvedValue(
|
56
|
+
url.startsWith('https://api.')
|
57
|
+
? { tag_name: 'v4.0.0' }
|
58
|
+
: [
|
59
|
+
{ locale: 'es-ES', track: 'ux' },
|
60
|
+
{ locale: 'es-ES', track: 'js' },
|
61
|
+
{ locale: 'pt-BR', track: 'ux' },
|
62
|
+
]
|
63
|
+
),
|
64
|
+
}));
|
65
|
+
|
66
|
+
return createAPI().projects.findMany({
|
67
|
+
tag: 'v3.0.0',
|
68
|
+
locale: 'es-ES',
|
69
|
+
track: 'ux',
|
70
|
+
})
|
71
|
+
.then((projects) => {
|
72
|
+
expect(projects).toEqual([{ locale: 'es-ES', track: 'ux' }]);
|
73
|
+
expect(global.fetch).toHaveBeenCalledTimes(1);
|
74
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
75
|
+
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v3.0.0/dist/projects.json',
|
76
|
+
);
|
77
|
+
});
|
78
|
+
});
|
79
|
+
|
80
|
+
// it should filter by tag, locale and track...
|
81
|
+
});
|
82
|
+
|
83
|
+
describe('findById', () => {
|
84
|
+
it('sends request to get latest version and then corresponding json', () => {
|
85
|
+
global.fetch = jest.fn().mockImplementation(async url => ({
|
86
|
+
status: 200,
|
87
|
+
json: jest.fn().mockResolvedValue(
|
88
|
+
url.startsWith('https://api.')
|
89
|
+
? { tag_name: 'v4.0.0' }
|
90
|
+
: {}
|
91
|
+
),
|
92
|
+
}));
|
93
|
+
|
94
|
+
return createAPI().projects.findById('cipher')
|
95
|
+
.then((project) => {
|
96
|
+
expect(project).toEqual({});
|
97
|
+
expect(global.fetch).toHaveBeenCalledTimes(2);
|
98
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
99
|
+
1,
|
100
|
+
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
101
|
+
);
|
102
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
103
|
+
2,
|
104
|
+
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/projects/cipher.json',
|
105
|
+
);
|
106
|
+
});
|
107
|
+
});
|
108
|
+
});
|
109
|
+
});
|
110
|
+
|
111
|
+
describe('topics', () => {
|
112
|
+
describe('findMany', () => {
|
113
|
+
it('sends request to get latest version and then corresponding json', () => {
|
114
|
+
global.fetch = jest.fn().mockImplementation(async url => ({
|
115
|
+
status: 200,
|
116
|
+
json: jest.fn().mockResolvedValue(
|
117
|
+
url.startsWith('https://api.')
|
118
|
+
? { tag_name: 'v4.0.0' }
|
119
|
+
: []
|
120
|
+
),
|
121
|
+
}));
|
122
|
+
|
123
|
+
return createAPI().topics.findMany()
|
124
|
+
.then((topics) => {
|
125
|
+
expect(topics).toEqual([]);
|
126
|
+
expect(global.fetch).toHaveBeenCalledTimes(2);
|
127
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
128
|
+
1,
|
129
|
+
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
130
|
+
);
|
131
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
132
|
+
2,
|
133
|
+
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/topics.json',
|
134
|
+
);
|
135
|
+
});
|
136
|
+
});
|
137
|
+
});
|
138
|
+
|
139
|
+
describe('findById', () => {
|
140
|
+
it('sends request to get latest version and then corresponding json', () => {
|
141
|
+
global.fetch = jest.fn().mockImplementation(async url => ({
|
142
|
+
status: 200,
|
143
|
+
json: jest.fn().mockResolvedValue(
|
144
|
+
url.startsWith('https://api.')
|
145
|
+
? { tag_name: 'v4.0.0' }
|
146
|
+
: {}
|
147
|
+
),
|
148
|
+
}));
|
149
|
+
|
150
|
+
return createAPI().topics.findById('javascript')
|
151
|
+
.then((topic) => {
|
152
|
+
expect(topic).toEqual({});
|
153
|
+
expect(global.fetch).toHaveBeenCalledTimes(2);
|
154
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
155
|
+
1,
|
156
|
+
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
157
|
+
);
|
158
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
159
|
+
2,
|
160
|
+
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/topics/javascript.json',
|
161
|
+
);
|
162
|
+
});
|
163
|
+
});
|
164
|
+
});
|
165
|
+
});
|
166
|
+
|
167
|
+
describe('learningObjectives', () => {
|
168
|
+
describe('findMany', () => {
|
169
|
+
it('sends request to get latest version and then corresponding json', () => {
|
170
|
+
global.fetch = jest.fn().mockImplementation(async url => ({
|
171
|
+
status: 200,
|
172
|
+
json: jest.fn().mockResolvedValue(
|
173
|
+
url.startsWith('https://api.')
|
174
|
+
? { tag_name: 'v4.0.0' }
|
175
|
+
: []
|
176
|
+
),
|
177
|
+
}));
|
178
|
+
|
179
|
+
return createAPI().learningObjectives.findMany()
|
180
|
+
.then((learningObjectives) => {
|
181
|
+
expect(learningObjectives).toEqual([]);
|
182
|
+
expect(global.fetch).toHaveBeenCalledTimes(2);
|
183
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
184
|
+
1,
|
185
|
+
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
186
|
+
);
|
187
|
+
expect(global.fetch).toHaveBeenNthCalledWith(
|
188
|
+
2,
|
189
|
+
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/learning-objectives.json',
|
190
|
+
);
|
191
|
+
});
|
192
|
+
});
|
193
|
+
});
|
194
|
+
});
|
package/lib/jobs.js
CHANGED
@@ -1,4 +1,22 @@
|
|
1
|
-
import { createModels } from './model';
|
2
|
-
import
|
1
|
+
import { createModels, extendSchemaDefinitions } from './model';
|
2
|
+
import schema from '../schemas/jobs.json';
|
3
3
|
|
4
|
-
|
4
|
+
const extended = {
|
5
|
+
Country: {
|
6
|
+
plural: 'countries',
|
7
|
+
},
|
8
|
+
Job: {
|
9
|
+
// inputProps: [],
|
10
|
+
// properties: {},
|
11
|
+
},
|
12
|
+
Company: {
|
13
|
+
plural: 'companies',
|
14
|
+
// inputProps: [],
|
15
|
+
// properties: {},
|
16
|
+
},
|
17
|
+
};
|
18
|
+
|
19
|
+
export const createAPI = (url, state) => createModels(url, state, {
|
20
|
+
...schema,
|
21
|
+
definitions: extendSchemaDefinitions(schema, extended),
|
22
|
+
});
|