workable 1.0.0 → 2.0.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile +1 -1
- data/Guardfile +3 -3
- data/README.md +5 -6
- data/Rakefile +3 -2
- data/lib/workable.rb +7 -4
- data/lib/workable/client.rb +106 -91
- data/lib/workable/collection.rb +29 -0
- data/lib/workable/errors.rb +6 -6
- data/lib/workable/transformation.rb +26 -0
- data/lib/workable/version.rb +1 -1
- data/spec/fixtures.rb +34 -122
- data/spec/fixtures/about.json +8 -0
- data/spec/fixtures/job.json +31 -0
- data/spec/fixtures/job_candidate.json +119 -0
- data/spec/fixtures/job_candidates.json +58 -0
- data/spec/fixtures/job_questions.json +34 -0
- data/spec/fixtures/jobs.json +73 -0
- data/spec/fixtures/members.json +32 -0
- data/spec/fixtures/new_candidate.json +60 -0
- data/spec/fixtures/new_candidate_response.json +109 -0
- data/spec/fixtures/recruiters.json +14 -0
- data/spec/fixtures/stages.json +40 -0
- data/spec/lib/workable/client_spec.rb +157 -121
- data/spec/lib/workable/collection_spec.rb +49 -0
- data/spec/lib/workable/transformation_spec.rb +38 -0
- data/spec/spec_helper.rb +6 -1
- data/workable.gemspec +7 -7
- metadata +32 -4
@@ -0,0 +1,73 @@
|
|
1
|
+
{
|
2
|
+
"jobs": [
|
3
|
+
{
|
4
|
+
"id": "61884e2",
|
5
|
+
"title": "Sales Intern",
|
6
|
+
"full_title": "Sales Intern - US/3/SI",
|
7
|
+
"shortcode": "GROOV003",
|
8
|
+
"code": "US/3/SI",
|
9
|
+
"state": "draft",
|
10
|
+
"department": "Sales",
|
11
|
+
"url": "https://groove-tech.workable.com/jobs/102268944",
|
12
|
+
"application_url": "https://groove-tech.workable.com/jobs/102268944/candidates/new",
|
13
|
+
"shortlink": "https://groove-tech.workable.com/j/GROOV003",
|
14
|
+
"location": {
|
15
|
+
"country": "United States",
|
16
|
+
"country_code": "US",
|
17
|
+
"region": "Oregon",
|
18
|
+
"region_code": "OR",
|
19
|
+
"city": "Portland",
|
20
|
+
"zip_code": "97201",
|
21
|
+
"telecommuting": false
|
22
|
+
},
|
23
|
+
"created_at": "2015-07-01T00:00:00Z"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"id": "1166bf8c",
|
27
|
+
"title": "Operations Manager",
|
28
|
+
"full_title": "Operations Manager - US/02/CM",
|
29
|
+
"shortcode": "GROOV001",
|
30
|
+
"code": "US/02/CM",
|
31
|
+
"state": "archived",
|
32
|
+
"department": "Operations",
|
33
|
+
"url": "https://groove-tech.workable.com/jobs/291945146",
|
34
|
+
"application_url": "https://groove-tech.workable.com/jobs/291945146/candidates/new",
|
35
|
+
"shortlink": "https://groove-tech.workable.com/j/GROOV001",
|
36
|
+
"location": {
|
37
|
+
"country": "United States",
|
38
|
+
"country_code": "US",
|
39
|
+
"region": "Illinois",
|
40
|
+
"region_code": "IL",
|
41
|
+
"city": "Chicago",
|
42
|
+
"zip_code": "60290",
|
43
|
+
"telecommuting": false
|
44
|
+
},
|
45
|
+
"created_at": "2015-05-07T00:00:00Z"
|
46
|
+
},
|
47
|
+
{
|
48
|
+
"id": "167636b1",
|
49
|
+
"title": "Office Manager",
|
50
|
+
"full_title": "Office Manager - US/4/OM",
|
51
|
+
"shortcode": "GROOV005",
|
52
|
+
"code": "US/4/OM",
|
53
|
+
"state": "published",
|
54
|
+
"department": "Administration",
|
55
|
+
"url": "https://groove-tech.workable.com/jobs/376844767",
|
56
|
+
"application_url": "https://groove-tech.workable.com/jobs/376844767/candidates/new",
|
57
|
+
"shortlink": "https://groove-tech.workable.com/j/GROOV005",
|
58
|
+
"location": {
|
59
|
+
"country": "United States",
|
60
|
+
"country_code": "US",
|
61
|
+
"region": "Illinois",
|
62
|
+
"region_code": "IL",
|
63
|
+
"city": "Chicago",
|
64
|
+
"zip_code": "60290",
|
65
|
+
"telecommuting": false
|
66
|
+
},
|
67
|
+
"created_at": "2015-06-06T00:00:00Z"
|
68
|
+
}
|
69
|
+
],
|
70
|
+
"paging": {
|
71
|
+
"next": "https://www.workable.com/spi/v3/accounts/subdomain/jobs?limit=3&since_id=2700d6df"
|
72
|
+
}
|
73
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
{
|
2
|
+
"members": [
|
3
|
+
{
|
4
|
+
"id": "13e0eb0e",
|
5
|
+
"name": "Eduardo Vallente",
|
6
|
+
"headline": "Operations Manager",
|
7
|
+
"email": "eduardo.vallente@workabledemo.com",
|
8
|
+
"role": "admin"
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"id": "19782abc",
|
12
|
+
"name": "Nadia Sawahla",
|
13
|
+
"headline": "Talent Manager",
|
14
|
+
"email": "nadia.sawahla@name.com",
|
15
|
+
"role": "recruiter"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"id": "3247e8c7",
|
19
|
+
"name": "Alexia Middleton",
|
20
|
+
"headline": "Commercial Director",
|
21
|
+
"email": "alexia.middleton@workabledemo.com",
|
22
|
+
"role": "simple"
|
23
|
+
},
|
24
|
+
{
|
25
|
+
"id": "3c00c3ac",
|
26
|
+
"name": "David Bodello",
|
27
|
+
"headline": "IT Specialist Recruiter",
|
28
|
+
"email": "david.bodellos@gmail.com",
|
29
|
+
"role": "recruiter"
|
30
|
+
}
|
31
|
+
]
|
32
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
{
|
2
|
+
"candidate": {
|
3
|
+
"name": "Jj Botha",
|
4
|
+
"firstname": "Jj",
|
5
|
+
"lastname": "Botha",
|
6
|
+
"headline": "Professional Administration Manager",
|
7
|
+
"summary": "A focussed, results-driven team player with many year experience in the field. Working my way up to management level, I have experience of every aspect of this role. I understand the challenges it brings, and have a proven track record of providing solutions.",
|
8
|
+
"address": "25772 Gustave Shore, Iowa, USA",
|
9
|
+
"phone": "1-859-557-6573",
|
10
|
+
"email": "jj_botha@fakemail.com",
|
11
|
+
"cover_letter": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
12
|
+
|
13
|
+
"education_entries": [
|
14
|
+
{ "degree": "MBA", "school": "University of Pennsylvania", "field_of_study": null, "start_date": "2008-03-01", "end_date": "2011-03-30" },
|
15
|
+
{ "degree": "B.S.", "school": "University of Chicago", "field_of_study": "Marketing Communication & Economics", "start_date": "2004-09-01", "end_date": "2007-03-30" }
|
16
|
+
],
|
17
|
+
|
18
|
+
"experience_entries": [
|
19
|
+
{
|
20
|
+
"title": "Sales Director",
|
21
|
+
"summary": null,
|
22
|
+
"start_date": "2011-03-01",
|
23
|
+
"end_date": "2014-03-30",
|
24
|
+
"current": false,
|
25
|
+
"company": "Vox Mobile",
|
26
|
+
"industry": "Telecommunications"
|
27
|
+
}
|
28
|
+
],
|
29
|
+
|
30
|
+
"answers": [
|
31
|
+
{
|
32
|
+
"question_key": "2128d717",
|
33
|
+
"body": "Planning"
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"question_key": "3399e6cd",
|
37
|
+
"choices": ["1e477229"]
|
38
|
+
}
|
39
|
+
],
|
40
|
+
|
41
|
+
"skills": [ "Travel Planning", "Problem Solving"],
|
42
|
+
"social_profiles": [
|
43
|
+
{
|
44
|
+
"type": "twitter",
|
45
|
+
"name": "Twitter",
|
46
|
+
"username": "jj_botha",
|
47
|
+
"url": "http://www.twitter.com/jj_botha"
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"type": "linkedin",
|
51
|
+
"name": "LinkedIn",
|
52
|
+
"url": "http://www.linkedin.com/in/jj_botha"
|
53
|
+
},
|
54
|
+
{
|
55
|
+
"type": "googleplus",
|
56
|
+
"url": "https://plus.google.com/6908286706342698"
|
57
|
+
}
|
58
|
+
]
|
59
|
+
}
|
60
|
+
}
|
@@ -0,0 +1,109 @@
|
|
1
|
+
{
|
2
|
+
"status": "created",
|
3
|
+
"candidate": {
|
4
|
+
"id": "3fc9a80f",
|
5
|
+
"name": "Jj Botha",
|
6
|
+
"firstname": null,
|
7
|
+
"lastname": null,
|
8
|
+
"headline": "Professional Administration Manager",
|
9
|
+
"image_url": null,
|
10
|
+
"account": {
|
11
|
+
"subdomain": "groove-tech",
|
12
|
+
"name": "Groove Tech"
|
13
|
+
},
|
14
|
+
"job": {
|
15
|
+
"shortcode": "GROOV005",
|
16
|
+
"title": "Office Manager"
|
17
|
+
},
|
18
|
+
"stage": "Sourced",
|
19
|
+
"disqualified": false,
|
20
|
+
"disqualified_at": null,
|
21
|
+
"disqualification_reason": null,
|
22
|
+
"sourced": true,
|
23
|
+
"profile_url": "https://groove-tech.workable.com/backend/jobs/376844767/candidates/1070179133",
|
24
|
+
"address": "25772 Gustave Shore, Iowa, USA",
|
25
|
+
"phone": "1-859-557-6573",
|
26
|
+
"email": "jj_botha@fakemail.com",
|
27
|
+
"outbound_mailbox": "b-6adwdc@outbound.dev-workable.mailgun.org",
|
28
|
+
"domain": null,
|
29
|
+
"uploader_id": null,
|
30
|
+
"created_at": "2015-07-09T10:55:53Z",
|
31
|
+
"updated_at": "2015-07-09T10:55:53Z",
|
32
|
+
"cover_letter": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
33
|
+
"summary": "A focussed, results-driven team player with many year experience in the field. Working my way up to management level, I have experience of every aspect of this role. I understand the challenges it brings, and have a proven track record of providing solutions.",
|
34
|
+
"education_entries": [
|
35
|
+
{
|
36
|
+
"degree": "MBA",
|
37
|
+
"school": "University of Pennsylvania",
|
38
|
+
"field_of_study": null,
|
39
|
+
"start_date": "2008-03-01",
|
40
|
+
"end_date": "2011-03-30"
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"degree": "B.S.",
|
44
|
+
"school": "University of Chicago",
|
45
|
+
"field_of_study": "Marketing Communication & Economics",
|
46
|
+
"start_date": "2004-09-01",
|
47
|
+
"end_date": "2007-03-30"
|
48
|
+
}
|
49
|
+
],
|
50
|
+
"experience_entries": [
|
51
|
+
{
|
52
|
+
"title": "Sales Director",
|
53
|
+
"summary": null,
|
54
|
+
"start_date": "2011-03-01",
|
55
|
+
"end_date": "2014-03-30",
|
56
|
+
"company": "Vox Mobile",
|
57
|
+
"industry": "Telecommunications",
|
58
|
+
"current": false
|
59
|
+
}
|
60
|
+
],
|
61
|
+
"skills": [
|
62
|
+
{
|
63
|
+
"name": "travel planning"
|
64
|
+
},
|
65
|
+
{
|
66
|
+
"name": "problem solving"
|
67
|
+
}
|
68
|
+
],
|
69
|
+
"answers": [
|
70
|
+
{
|
71
|
+
"question": {
|
72
|
+
"body": "Explain one aspect of this role you believe you will excel at."
|
73
|
+
},
|
74
|
+
"answer": {
|
75
|
+
"body": "<p>Planning</p>"
|
76
|
+
}
|
77
|
+
},
|
78
|
+
{
|
79
|
+
"question": {
|
80
|
+
"body": "How many years administrative experience do you have?"
|
81
|
+
},
|
82
|
+
"answer": {
|
83
|
+
"choices": [
|
84
|
+
{
|
85
|
+
"body": "Over 5 years"
|
86
|
+
}
|
87
|
+
]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
],
|
91
|
+
"resume_url": null,
|
92
|
+
"social_profiles": [
|
93
|
+
{
|
94
|
+
"type": "twitter",
|
95
|
+
"username": "jj_botha",
|
96
|
+
"url": "http://www.twitter.com/jj_botha"
|
97
|
+
},
|
98
|
+
{
|
99
|
+
"type": "linkedin",
|
100
|
+
"url": "http://www.linkedin.com/in/jj_botha"
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"type": "googleplus",
|
104
|
+
"url": "https://plus.google.com/6908286706342698"
|
105
|
+
}
|
106
|
+
],
|
107
|
+
"tags": []
|
108
|
+
}
|
109
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
{
|
2
|
+
"stages": [
|
3
|
+
{
|
4
|
+
"slug": "sourced",
|
5
|
+
"name": "Sourced",
|
6
|
+
"kind": "sourced",
|
7
|
+
"position": 0
|
8
|
+
},
|
9
|
+
{
|
10
|
+
"slug": "applied",
|
11
|
+
"name": "Applied",
|
12
|
+
"kind": "applied",
|
13
|
+
"position": 1
|
14
|
+
},
|
15
|
+
{
|
16
|
+
"slug": "phone-screen",
|
17
|
+
"name": "Phone Screen",
|
18
|
+
"kind": "phone-screen",
|
19
|
+
"position": 2
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"slug": "interview",
|
23
|
+
"name": "Interview",
|
24
|
+
"kind": "interview",
|
25
|
+
"position": 3
|
26
|
+
},
|
27
|
+
{
|
28
|
+
"slug": "offer",
|
29
|
+
"name": "Offer",
|
30
|
+
"kind": "offer",
|
31
|
+
"position": 4
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"slug": "hired",
|
35
|
+
"name": "Hired",
|
36
|
+
"kind": "hired",
|
37
|
+
"position": 5
|
38
|
+
}
|
39
|
+
]
|
40
|
+
}
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Workable::Client do
|
4
|
+
let(:client) { described_class.new(api_key: 'test', subdomain: 'subdomain') }
|
5
|
+
let(:headers){ { 'Authorization' => 'Bearer test', 'User-Agent' => 'Workable Ruby Client' } }
|
4
6
|
|
5
7
|
describe '#new' do
|
6
8
|
it 'raises an error on missing api_key / subdomain' do
|
@@ -14,176 +16,210 @@ describe Workable::Client do
|
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
17
|
-
describe '#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
describe '#about' do
|
20
|
+
it 'returns information about company as a hash' do
|
21
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/')
|
22
|
+
.to_return(status: 200, body: about_json_fixture)
|
23
|
+
expect(client.about['name']).to eq('Groove Tech')
|
24
|
+
end
|
25
|
+
end
|
24
26
|
|
25
|
-
|
27
|
+
describe '#members' do
|
28
|
+
it 'returns array of members' do
|
29
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/members')
|
30
|
+
.to_return(status: 200, body: members_json_fixture)
|
31
|
+
|
32
|
+
expect(client.members).to be_kind_of(Array)
|
33
|
+
expect(client.members[0]).to eq(
|
34
|
+
'id' => '13e0eb0e',
|
35
|
+
'name' => 'Eduardo Vallente',
|
36
|
+
'headline' => 'Operations Manager',
|
37
|
+
'email' => 'eduardo.vallente@workabledemo.com',
|
38
|
+
'role' => 'admin'
|
39
|
+
)
|
26
40
|
end
|
41
|
+
end
|
27
42
|
|
28
|
-
|
29
|
-
|
30
|
-
|
43
|
+
describe '#recruiters' do
|
44
|
+
it 'returns array of recruiters' do
|
45
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/recruiters')
|
46
|
+
.to_return(status: 200, body: recruiters_json_fixture)
|
31
47
|
|
32
|
-
expect
|
48
|
+
expect(client.recruiters).to be_kind_of(Array)
|
49
|
+
expect(client.recruiters[0]).to eq(
|
50
|
+
'id' => '19782abc',
|
51
|
+
'name' => 'Nadia Sawahla',
|
52
|
+
'email' => 'nadia.sawahla@name.com'
|
53
|
+
)
|
33
54
|
end
|
55
|
+
end
|
34
56
|
|
35
|
-
|
36
|
-
|
37
|
-
|
57
|
+
describe '#stages' do
|
58
|
+
it 'returns array of stages' do
|
59
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/stages')
|
60
|
+
.to_return(status: 200, body: stages_json_fixture)
|
38
61
|
|
39
|
-
|
62
|
+
expect(client.stages).to be_kind_of(Array)
|
63
|
+
expect(client.stages[0]).to eq(
|
64
|
+
'slug' => 'sourced',
|
65
|
+
'name' => 'Sourced',
|
66
|
+
'kind' => 'sourced',
|
67
|
+
'position' => 0
|
68
|
+
)
|
40
69
|
end
|
41
70
|
end
|
42
71
|
|
43
|
-
describe '#
|
44
|
-
|
72
|
+
describe '#jobs' do
|
73
|
+
context 'happy path' do
|
74
|
+
before do
|
75
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs')
|
76
|
+
.with(headers: headers)
|
77
|
+
.to_return(status: 200, body: jobs_index_json_fixture)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returns collection of posted jobs' do
|
81
|
+
expect(client.jobs).to be_kind_of(Workable::Collection)
|
82
|
+
expect(client.jobs.data).to be_kind_of(Array)
|
83
|
+
expect(client.jobs.data[0]).to include('title' => 'Sales Intern', 'full_title' => 'Sales Intern - US/3/SI')
|
84
|
+
expect(client.jobs.data.size).to eq(3)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'includes next page method that returns next collection' do
|
88
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs?limit=3&since_id=2700d6df')
|
89
|
+
.with(headers: headers)
|
90
|
+
.to_return(status: 200, body: jobs_index_json_fixture)
|
91
|
+
|
92
|
+
jobs = client.jobs.fetch_next_page
|
93
|
+
expect(jobs).to be_kind_of(Workable::Collection)
|
94
|
+
expect(client.jobs.data).to be_kind_of(Array)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'sad path' do
|
99
|
+
it 'raises exception on not authorized error (401)' do
|
100
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs')
|
101
|
+
.to_return(status: 401, body: '{"error":"Not authorized"}')
|
102
|
+
|
103
|
+
expect { client.jobs }.to raise_error(Workable::Errors::NotAuthorized)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'raises exception when status code differs from 200' do
|
107
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs')
|
108
|
+
.to_return(status: 500, body: '')
|
109
|
+
|
110
|
+
expect { client.jobs }.to raise_error(Workable::Errors::InvalidResponse)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
45
114
|
|
115
|
+
describe '#job_details' do
|
46
116
|
it 'returns details of given job' do
|
47
|
-
stub_request(:get,
|
48
|
-
.to_return(status: 200, body: job_json_fixture
|
117
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/03FF356C8B')
|
118
|
+
.to_return(status: 200, body: job_json_fixture)
|
49
119
|
|
50
120
|
expect(client.job_details('03FF356C8B')).to be_kind_of(Hash)
|
51
121
|
end
|
52
122
|
|
53
123
|
it 'raises an exception when job is not found' do
|
54
|
-
stub_request(:get,
|
55
|
-
.to_return(status: 404, body: '{"error":"Not found"}'
|
124
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/invalid')
|
125
|
+
.to_return(status: 404, body: '{"error":"Not found"}')
|
56
126
|
|
57
127
|
expect { client.job_details('invalid') }.to raise_error(Workable::Errors::NotFound)
|
58
128
|
end
|
59
129
|
end
|
60
130
|
|
61
131
|
describe '#job_questions' do
|
62
|
-
let(:client){ described_class.new(api_key: 'test', subdomain: 'subdomain') }
|
63
|
-
|
64
132
|
it 'returns questions for given job' do
|
65
|
-
stub_request(:get,
|
66
|
-
.to_return(status: 200, body: job_questions_json_fixture
|
133
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/03FF356C8B/questions')
|
134
|
+
.to_return(status: 200, body: job_questions_json_fixture)
|
67
135
|
|
68
|
-
|
136
|
+
questions = client.job_questions('03FF356C8B')
|
137
|
+
expect(questions).to be_kind_of(Array)
|
138
|
+
expect(questions[0]['body']).to eq('Explain one aspect of this role you believe you will excel at.')
|
69
139
|
end
|
70
|
-
|
71
140
|
end
|
72
141
|
|
73
|
-
describe
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
142
|
+
describe '#job_members' do
|
143
|
+
it "returns array of job's members" do
|
144
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/job_slug/members')
|
145
|
+
.to_return(status: 200, body: members_json_fixture)
|
146
|
+
|
147
|
+
expect(client.job_members('job_slug')).to be_kind_of(Array)
|
148
|
+
expect(client.job_members('job_slug')[0]).to eq(
|
149
|
+
'id' => '13e0eb0e',
|
150
|
+
'name' => 'Eduardo Vallente',
|
151
|
+
'headline' => 'Operations Manager',
|
152
|
+
'email' => 'eduardo.vallente@workabledemo.com',
|
153
|
+
'role' => 'admin'
|
154
|
+
)
|
86
155
|
end
|
156
|
+
end
|
87
157
|
|
88
|
-
|
89
|
-
|
90
|
-
|
158
|
+
describe 'job_recruiters' do
|
159
|
+
it "returns array of job's recruiters" do
|
160
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/job_slug/recruiters')
|
161
|
+
.to_return(status: 200, body: recruiters_json_fixture)
|
91
162
|
|
92
|
-
|
93
|
-
expect(
|
163
|
+
expect(client.job_recruiters('job_slug')).to be_kind_of(Array)
|
164
|
+
expect(client.job_recruiters('job_slug')[0]).to eq(
|
165
|
+
'id' => '19782abc',
|
166
|
+
'name' => 'Nadia Sawahla',
|
167
|
+
'email' => 'nadia.sawahla@name.com'
|
168
|
+
)
|
94
169
|
end
|
95
170
|
end
|
96
171
|
|
97
172
|
describe '#job_candidates' do
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
expect(client.job_candidates('03FF356C8B')).to be_kind_of(Array)
|
105
|
-
end
|
173
|
+
context 'happy path' do
|
174
|
+
let(:candidates){ client.job_candidates('03FF356C8B') }
|
175
|
+
before do
|
176
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/03FF356C8B/candidates')
|
177
|
+
.to_return(status: 200, body: job_candidates_json_fixture)
|
178
|
+
end
|
106
179
|
|
107
|
-
|
108
|
-
|
109
|
-
.
|
110
|
-
|
111
|
-
expect { client.jobs }.to raise_error(Workable::Errors::RequestToLong)
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
describe '#stages' do
|
117
|
-
let(:client){ described_class.new(api_key: 'test', subdomain: 'subdomain') }
|
180
|
+
it 'returns collection of candidates for given job' do
|
181
|
+
expect(candidates).to be_kind_of(Workable::Collection)
|
182
|
+
expect(candidates.data[0]['name']).to eq('Lakita Marrero')
|
183
|
+
end
|
118
184
|
|
119
|
-
|
120
|
-
|
121
|
-
|
185
|
+
it 'includes next page method that returns next collection' do
|
186
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/subdomain/candidates?limit=3&since_id=2700d6df')
|
187
|
+
.with(headers: headers)
|
188
|
+
.to_return(status: 200, body: job_candidates_json_fixture)
|
122
189
|
|
123
|
-
|
190
|
+
next_candidates = candidates.fetch_next_page
|
191
|
+
expect(next_candidates).to be_kind_of(Workable::Collection)
|
192
|
+
expect(next_candidates.data).to be_kind_of(Array)
|
193
|
+
end
|
124
194
|
end
|
125
|
-
end
|
126
195
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
subdomain: 'subdomain',
|
132
|
-
transform_to: {
|
133
|
-
candidate: OpenStruct.method(:new)
|
134
|
-
}
|
135
|
-
)
|
136
|
-
}
|
196
|
+
context 'sad path' do
|
197
|
+
it 'raises exception on to long requests' do
|
198
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/03FF356C8B/candidates')
|
199
|
+
.to_return(status: 503, body: '{"error":"Not authorized"}')
|
137
200
|
|
138
|
-
|
139
|
-
|
140
|
-
expect(result).to be_kind_of(OpenStruct)
|
141
|
-
expect(result.name).to eq("Tom")
|
201
|
+
expect { client.job_candidates('03FF356C8B') }.to raise_error(Workable::Errors::RequestToLong)
|
202
|
+
end
|
142
203
|
end
|
143
204
|
end
|
144
205
|
|
145
|
-
describe
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
subdomain: 'subdomain',
|
150
|
-
transform_from: {
|
151
|
-
candidate: lambda { |input| input.marshal_dump }
|
152
|
-
}
|
153
|
-
)
|
154
|
-
}
|
206
|
+
describe '#job_candidate' do
|
207
|
+
it 'returns detailed info about given candidate' do
|
208
|
+
stub_request(:get, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/job-slug/candidates/some-id')
|
209
|
+
.to_return(status: 200, body: job_candidate_json_fixture)
|
155
210
|
|
156
|
-
|
157
|
-
input = client.send(:transform_from, :candidate, OpenStruct.new({:name => "Tom"}))
|
158
|
-
expect(input).to be_kind_of(Hash)
|
159
|
-
expect(input[:name]).to eq("Tom")
|
211
|
+
expect(client.job_candidate('job-slug', 'some-id')['name']).to eq('Cindy Sawyers')
|
160
212
|
end
|
161
213
|
end
|
162
214
|
|
163
|
-
describe
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
expect(result).to be_kind_of(OpenStruct)
|
169
|
-
expect(result.name).to eq("Tom")
|
170
|
-
end
|
171
|
-
|
172
|
-
it "transforms many" do
|
173
|
-
data = client.send(:transform, OpenStruct.method(:new), [{:name => "Tom"}, {:name => "Alice"}])
|
174
|
-
expect(data).to be_kind_of(Array)
|
175
|
-
expect(data.map(&:class)).to eq([OpenStruct, OpenStruct])
|
176
|
-
end
|
215
|
+
describe '#create_job_candidate' do
|
216
|
+
it 'POSTs requests and parses response' do
|
217
|
+
stub_request(:post, 'https://www.workable.com/spi/v3/accounts/subdomain/jobs/slug/candidates')
|
218
|
+
.with(body: new_candiate_hash_fixture.to_json)
|
219
|
+
.to_return(status: 200, body: new_candiate_response_json_fixture)
|
177
220
|
|
178
|
-
|
179
|
-
|
180
|
-
expect(data).to eq(nil)
|
181
|
-
end
|
182
|
-
|
183
|
-
it "does not transform without transformation" do
|
184
|
-
data = client.send(:transform, nil, OpenStruct.new({:slug => "sourced"}))
|
185
|
-
expect(data).to eq(OpenStruct.new({:slug => "sourced"}))
|
221
|
+
candidate = client.create_job_candidate(new_candiate_hash_fixture, 'slug')
|
222
|
+
expect(candidate['id']).to eq('3fc9a80f')
|
186
223
|
end
|
187
224
|
end
|
188
|
-
|
189
225
|
end
|