@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.
@@ -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
+ [![Node.js CI](https://github.com/Laboratoria/sdk-js/actions/workflows/node.js.yml/badge.svg)](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
- // app.learningObjectives.
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 setState = (authUser, user) => {
31
- Object.assign(state, { authUser, user });
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
- setState(null, null);
34
+ Object.assign(state, { authUser: null, user: null });
38
35
  return fn(state);
39
36
  }
40
- createClient(coreApiUrl, authUser)(`/users/${authUser.uid}`)
37
+ Object.assign(state, { authUser });
38
+ coreAPI.user.findById(authUser.uid)
41
39
  .then((user) => {
42
- Object.assign(user, {
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
- setState(null, null)
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 { createClient } from './lib/client.js';
8
+ import { createAPI as createCoreAPI } from './lib/core';
9
9
  import { createApp } from './index.js';
10
10
 
11
- jest.mock('./lib/client.js');
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 and add isStaff, isManager, etc', (done) => {
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
- createClient().mockResolvedValueOnce(userMock);
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
- createClient().mockRejectedValueOnce(error);
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
- 'locale',
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
- properties: {
41
- program: {
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
- 'project',
55
- 'stage',
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 { delete: _, ...userAPI } = createModel(coreApiUrl, state, 'users', schemas.user);
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 jobsSchema from '../schemas/jobs.json';
1
+ import { createModels, extendSchemaDefinitions } from './model';
2
+ import schema from '../schemas/jobs.json';
3
3
 
4
- export const createAPI = (url, state) => createModels(url, state, jobsSchema);
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
+ });