Hello world github/linguist#1 cool, and #1!
\n'); 28 | done(); 29 | }).catch(done); 30 | }); 31 | 32 | it('should convert markdown to html as GFM', function(done) { 33 | const options = { 34 | text: 'Hello world github/linguist#1 **cool**, and #1!', 35 | mode: 'gfm', 36 | context: 'github/gollum' 37 | }; 38 | markdown.render(options) 39 | .then(function({data: html}) { 40 | expect(html).to.be('Hello world github/linguist#1 cool, and #1!
'); // eslint-disable-line 41 | done(); 42 | }).catch(done); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /test/organization.spec.js: -------------------------------------------------------------------------------- 1 | import expect from 'must'; 2 | 3 | import Github from '../lib/GitHub'; 4 | import testUser from './fixtures/user.json'; 5 | import {assertSuccessful, assertArray} from './helpers/callbacks'; 6 | import getTestRepoName from './helpers/getTestRepoName'; 7 | 8 | describe('Organization', function() { 9 | let github; 10 | const ORG_NAME = 'github-tools'; 11 | const MEMBER_NAME = 'clayreimann'; 12 | 13 | before(function() { 14 | github = new Github({ 15 | username: testUser.USERNAME, 16 | password: testUser.PASSWORD, 17 | auth: 'basic' 18 | }); 19 | 20 | }); 21 | 22 | describe('reading', function() { 23 | let organization; 24 | 25 | before(function() { 26 | organization = github.getOrganization(ORG_NAME); 27 | }); 28 | 29 | it('should show user\'s organisation repos', function(done) { 30 | organization.getRepos(assertArray(done)); 31 | }); 32 | 33 | it('should list the users in the organization', function(done) { 34 | organization.listMembers() 35 | .then(function({data: members}) { 36 | expect(members).to.be.an.array(); 37 | 38 | let hasClayReimann = members.reduce((found, member) => member.login === MEMBER_NAME || found, false); 39 | expect(hasClayReimann).to.be.true(); 40 | 41 | done(); 42 | }).catch(done); 43 | }); 44 | 45 | it('should test for membership', function() { 46 | return organization.isMember(MEMBER_NAME) 47 | .then(function(isMember) { 48 | expect(isMember).to.be.true(); 49 | }); 50 | }); 51 | }); 52 | 53 | describe('creating/updating', function() { 54 | let organization; 55 | const testRepoName = getTestRepoName(); 56 | 57 | before(function() { 58 | organization = github.getOrganization(testUser.ORGANIZATION); 59 | }); 60 | 61 | it('should create an organization repo', function(done) { 62 | const options = { 63 | name: testRepoName, 64 | description: 'test create organization repo', 65 | homepage: 'https://github.com/', 66 | private: false, 67 | has_issues: true, // eslint-disable-line 68 | has_wiki: true, // eslint-disable-line 69 | has_downloads: true // eslint-disable-line 70 | }; 71 | 72 | organization.createRepo(options, assertSuccessful(done, function(err, repo) { 73 | expect(repo.name).to.equal(testRepoName); 74 | expect(repo.full_name).to.equal(`${testUser.ORGANIZATION}/${testRepoName}`); // eslint-disable-line 75 | done(); 76 | })); 77 | }); 78 | 79 | // TODO: The longer this is in place the slower it will get if we don't cleanup random test teams 80 | it('should list the teams in the organization', function() { 81 | return organization.getTeams() 82 | .then(({data}) => { 83 | const hasTeam = data.reduce( 84 | (found, member) => member.slug === 'fixed-test-team-1' || found, 85 | false); 86 | 87 | expect(hasTeam).to.be.true(); 88 | }); 89 | }); 90 | 91 | it('should create an organization team', function(done) { 92 | const options = { 93 | name: testRepoName, 94 | description: 'Created by unit tests', 95 | privacy: 'secret' 96 | }; 97 | 98 | organization.createTeam(options, assertSuccessful(done, function(err, team) { 99 | expect(team.name).to.equal(testRepoName); 100 | expect(team.organization.login).to.equal(testUser.ORGANIZATION); // jscs:ignore 101 | done(); 102 | })); 103 | }); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /test/rate-limit.spec.js: -------------------------------------------------------------------------------- 1 | import expect from 'must'; 2 | 3 | import Github from '../lib/GitHub'; 4 | import testUser from './fixtures/user.json'; 5 | import {assertSuccessful} from './helpers/callbacks'; 6 | 7 | describe('RateLimit', function() { 8 | let github; 9 | let rateLimit; 10 | 11 | before(function() { 12 | github = new Github({ 13 | username: testUser.USERNAME, 14 | password: testUser.PASSWORD, 15 | auth: 'basic' 16 | }); 17 | 18 | rateLimit = github.getRateLimit(); 19 | }); 20 | 21 | it('should get rate limit', function(done) { 22 | rateLimit.getRateLimit(assertSuccessful(done, function(err, rateInfo) { 23 | const rate = rateInfo.rate; 24 | 25 | expect(rate).to.be.an.object(); 26 | expect(rate).to.have.own('limit'); 27 | expect(rate).to.have.own('remaining'); 28 | expect(rate.limit).to.be.a.number(); 29 | expect(rate.remaining).to.be.a.number(); 30 | expect(rate.remaining).to.be.at.most(rateInfo.rate.limit); 31 | 32 | done(); 33 | })); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/repository.spec.js: -------------------------------------------------------------------------------- 1 | import expect from 'must'; 2 | 3 | import Github from '../lib/GitHub'; 4 | import testUser from './fixtures/user.json'; 5 | import loadImage from './fixtures/imageBlob'; 6 | import {assertSuccessful, assertFailure} from './helpers/callbacks'; 7 | import getTestRepoName from './helpers/getTestRepoName'; 8 | 9 | describe('Repository', function() { 10 | let github; 11 | let remoteRepo; 12 | let user; 13 | let imageB64; 14 | let imageBlob; 15 | const testRepoName = getTestRepoName(); 16 | const v10SHA = '20fcff9129005d14cc97b9d59b8a3d37f4fb633b'; 17 | const statusUrl = 'https://api.github.com/repos/michael/github/statuses/20fcff9129005d14cc97b9d59b8a3d37f4fb633b'; 18 | 19 | before(function(done) { 20 | github = new Github({ 21 | username: testUser.USERNAME, 22 | password: testUser.PASSWORD 23 | }); 24 | 25 | loadImage(function(b64, blob) { 26 | imageB64 = b64; 27 | imageBlob = blob; 28 | done(); 29 | }); 30 | }); 31 | 32 | describe('reading', function() { 33 | before(function() { 34 | remoteRepo = github.getRepo('michael', 'github'); 35 | }); 36 | 37 | it('should get repo details', function(done) { 38 | remoteRepo.getDetails(assertSuccessful(done, function(err, repo) { 39 | expect(repo).to.have.own('full_name', 'michael/github'); 40 | 41 | done(); 42 | })); 43 | }); 44 | 45 | it('should get blob', function(done) { 46 | remoteRepo.getSha('master', 'README.md', assertSuccessful(done, function(err, response) { 47 | remoteRepo.getBlob(response.sha, assertSuccessful(done, function(err, content) { 48 | expect(content).to.be.include('# Github.js'); 49 | 50 | done(); 51 | })); 52 | })); 53 | }); 54 | 55 | it('should get a branch', function(done) { 56 | remoteRepo.getBranch('master', assertSuccessful(done, function(err, content) { 57 | expect(content.name).to.be('master'); 58 | 59 | done(); 60 | })); 61 | }); 62 | 63 | it('should show repo contents', function(done) { 64 | remoteRepo.getContents('master', '', false, assertSuccessful(done, function(err, contents) { 65 | expect(contents).to.be.an.array(); 66 | 67 | const readme = contents.filter(function(content) { 68 | return content.path === 'README.md'; 69 | }); 70 | 71 | expect(readme).to.have.length(1); 72 | expect(readme[0]).to.have.own('type', 'file'); 73 | 74 | done(); 75 | })); 76 | }); 77 | 78 | it('should show repo content raw', function(done) { 79 | remoteRepo.getContents('master', 'README.md', 'raw', assertSuccessful(done, function(err, text) { 80 | expect(text).to.contain('# Github.js'); 81 | 82 | done(); 83 | })); 84 | }); 85 | 86 | it('should show repo readme', function(done) { 87 | remoteRepo.getReadme('master', 'raw', assertSuccessful(done, function(err, text) { 88 | expect(text).to.contain('# Github.js'); 89 | 90 | done(); 91 | })); 92 | }); 93 | 94 | it('should get ref from repo', function(done) { 95 | remoteRepo.getRef('heads/master', assertSuccessful(done)); 96 | }); 97 | 98 | it('should get tree', function(done) { 99 | remoteRepo.getTree('master', assertSuccessful(done, function(err, response) { 100 | let {tree} = response; 101 | expect(tree).to.be.an.array(); 102 | expect(tree.length).to.be.above(0); 103 | 104 | done(); 105 | })); 106 | }); 107 | 108 | it('should fork repo', function(done) { 109 | remoteRepo.fork(assertSuccessful(done)); 110 | }); 111 | 112 | it('should list forks of repo', function(done) { 113 | remoteRepo.listForks(assertSuccessful(done, function(err, forks) { 114 | expect(forks).to.be.an.array(); 115 | expect(forks.length).to.be.above(0); 116 | done(); 117 | })); 118 | }); 119 | 120 | it('should list commits with no options', function(done) { 121 | remoteRepo.listCommits(null, assertSuccessful(done, function(err, commits) { 122 | expect(commits).to.be.an.array(); 123 | expect(commits.length).to.be.above(0); 124 | 125 | expect(commits[0]).to.have.own('commit'); 126 | expect(commits[0]).to.have.own('author'); 127 | 128 | done(); 129 | })); 130 | }); 131 | 132 | it('should list commits with all options', function(done) { 133 | const since = new Date(2015, 0, 1); 134 | const until = new Date(2016, 0, 20); 135 | const options = { 136 | sha: 'master', 137 | path: 'test', 138 | author: 'AurelioDeRosa', 139 | since, 140 | until 141 | }; 142 | 143 | remoteRepo.listCommits(options, assertSuccessful(done, function(err, commits) { 144 | expect(commits).to.be.an.array(); 145 | expect(commits.length).to.be.above(0); 146 | 147 | const commit = commits[0]; 148 | const commitDate = new Date(commit.commit.author.date); 149 | 150 | expect(commit).to.have.own('commit'); 151 | expect(commit.author).to.have.own('login', 'AurelioDeRosa'); 152 | expect(commitDate.getTime()).to.be.between(since.getTime(), until.getTime()); 153 | done(); 154 | })); 155 | }); 156 | 157 | it('should get the latest commit from master', function(done) { 158 | remoteRepo.getSingleCommit('master', assertSuccessful(done, function(err, commit) { 159 | expect(commit).to.have.own('sha'); 160 | expect(commit).to.have.own('commit'); 161 | expect(commit).to.have.own('author'); 162 | 163 | done(); 164 | })); 165 | }); 166 | 167 | it('should fail when null ref is passed', function(done) { 168 | remoteRepo.getSingleCommit(null, assertFailure(done, function(err) { 169 | expect(err.status).to.be(404); 170 | done(); 171 | })); 172 | }); 173 | 174 | it('should show repo contributors', function(done) { 175 | remoteRepo.getContributors(assertSuccessful(done, function(err, contributors) { 176 | if (!(contributors instanceof Array)) { 177 | console.log(JSON.stringify(contributors, null, 2)); // eslint-disable-line 178 | } 179 | expect(contributors).to.be.an.array(); 180 | expect(contributors.length).to.be.above(1); 181 | 182 | const contributor = contributors[0]; 183 | 184 | expect(contributor).to.have.own('author'); 185 | expect(contributor).to.have.own('total'); 186 | expect(contributor).to.have.own('weeks'); 187 | 188 | done(); 189 | })); 190 | }); 191 | 192 | // @TODO repo.branch, repo.pull 193 | 194 | it('should list repo branches', function(done) { 195 | remoteRepo.listBranches(assertSuccessful(done)); 196 | }); 197 | 198 | it('should get commit from repo', function(done) { 199 | remoteRepo.getCommit(v10SHA, assertSuccessful(done, function(err, commit) { 200 | expect(commit.message).to.equal('v0.10.4'); 201 | expect(commit.author.date).to.equal('2015-03-20T17:01:42Z'); 202 | 203 | done(); 204 | })); 205 | }); 206 | 207 | it('should get statuses for a SHA from a repo', function(done) { 208 | remoteRepo.listStatuses(v10SHA, assertSuccessful(done, function(err, statuses) { 209 | expect(statuses).to.be.an.array(); 210 | expect(statuses.length).to.equal(6); 211 | 212 | const correctUrls = statuses.every(function(status) { 213 | return status.url === statusUrl; 214 | }); 215 | 216 | expect(correctUrls).to.be(true); 217 | 218 | done(); 219 | })); 220 | }); 221 | 222 | it('should get a SHA from a repo', function(done) { 223 | remoteRepo.getSha('master', '.gitignore', assertSuccessful(done)); 224 | }); 225 | 226 | it('should get a repo by fullname', function(done) { 227 | const repoByName = github.getRepo('michael/github'); 228 | 229 | repoByName.getDetails(assertSuccessful(done, function(err, repo) { 230 | expect(repo).to.have.own('full_name', 'michael/github'); 231 | 232 | done(); 233 | })); 234 | }); 235 | 236 | it('should check if the repo is starred', function(done) { 237 | remoteRepo.isStarred(assertSuccessful(done, function(err, result) { 238 | expect(result).to.equal(false); 239 | 240 | done(); 241 | })); 242 | }); 243 | }); 244 | 245 | describe('creating/modifiying', function() { 246 | const fileName = 'test.md'; 247 | 248 | const initialText = 'This is a test.'; 249 | const initialMessage = 'This is my 44 character long commit message.'; 250 | 251 | const updatedText = 'This file has been updated.'; 252 | const updatedMessage = 'This is my 51 character long update commit message.'; 253 | 254 | const fileToDelete = 'tmp.md'; 255 | const deleteMessage = 'This is my 51 character long delete commit message.'; 256 | 257 | const unicodeFileName = '\u4E2D\u6587\u6D4B\u8BD5.md'; 258 | const unicodeText = '\u00A1\u00D3i de m\u00ED, que verg\u00FCenza!'; 259 | const unicodeMessage = 'Such na\u00EFvet\u00E9\u2026'; 260 | 261 | const imageFileName = 'image.png'; 262 | 263 | const releaseTag = 'foo'; 264 | const releaseName = 'My awesome release'; 265 | const releaseBody = 'This is my 49 character long release description.'; 266 | let sha; 267 | let releaseId; 268 | 269 | before(function() { 270 | user = github.getUser(); 271 | remoteRepo = github.getRepo(testUser.USERNAME, testRepoName); 272 | }); 273 | 274 | // 200ms between tests so that Github has a chance to settle 275 | beforeEach(function(done) { 276 | setTimeout(done, 200); 277 | }); 278 | 279 | it('should create repo', function(done) { 280 | const repoDef = { 281 | name: testRepoName 282 | }; 283 | 284 | user.createRepo(repoDef, assertSuccessful(done, function(err, repo) { 285 | expect(repo).to.have.own('name', testRepoName); 286 | 287 | done(); 288 | })); 289 | }); 290 | 291 | it('should show repo collaborators', function(done) { 292 | remoteRepo.getCollaborators(assertSuccessful(done, function(err, collaborators) { 293 | if (!(collaborators instanceof Array)) { 294 | console.log(JSON.stringify(collaborators, null, 2)); // eslint-disable-line 295 | } 296 | expect(collaborators).to.be.an.array(); 297 | expect(collaborators).to.have.length(1); 298 | 299 | const collaborator = collaborators[0]; 300 | 301 | expect(collaborator).to.have.own('login', testUser.USERNAME); 302 | expect(collaborator).to.have.own('id'); 303 | expect(collaborator).to.have.own('permissions'); 304 | 305 | done(); 306 | })); 307 | }); 308 | 309 | it('should test whether user is collaborator', function(done) { 310 | remoteRepo.isCollaborator(testUser.USERNAME, assertSuccessful(done)); 311 | }); 312 | 313 | it('should write to repo', function(done) { 314 | remoteRepo.writeFile('master', fileName, initialText, initialMessage, assertSuccessful(done, function() { 315 | remoteRepo.getContents('master', fileName, 'raw', assertSuccessful(done, function(err, fileText) { 316 | expect(fileText).to.be(initialText); 317 | 318 | done(); 319 | })); 320 | })); 321 | }); 322 | 323 | it('should rename files', function(done) { 324 | remoteRepo.writeFile('master', fileName, initialText, initialMessage, assertSuccessful(done, function() { 325 | remoteRepo.move('master', fileName, 'new_name', assertSuccessful(done, function() { 326 | remoteRepo.getContents('master', fileName, 'raw', assertFailure(done, function(err) { 327 | expect(err.status).to.be(404); 328 | remoteRepo.getContents('master', 'new_name', 'raw', assertSuccessful(done, function(err, fileText) { 329 | expect(fileText).to.be(initialText); 330 | 331 | done(); 332 | })); 333 | })); 334 | })); 335 | })); 336 | }); 337 | 338 | it('should create a new branch', function(done) { 339 | remoteRepo.createBranch('master', 'dev', assertSuccessful(done, function(err, branch) { 340 | expect(branch).to.have.property('ref', 'refs/heads/dev'); 341 | expect(branch.object).to.have.property('sha'); 342 | 343 | done(); 344 | })); 345 | }); 346 | 347 | it('should write to repo branch', function(done) { 348 | remoteRepo.writeFile('dev', fileName, updatedText, updatedMessage, assertSuccessful(done, function() { 349 | remoteRepo.getContents('dev', fileName, 'raw', assertSuccessful(done, function(err, fileText) { 350 | expect(fileText).to.be(updatedText); 351 | 352 | done(); 353 | })); 354 | })); 355 | }); 356 | 357 | it('should compare two branches', function(done) { 358 | remoteRepo.createBranch('master', 'compare', assertSuccessful(done, function() { 359 | remoteRepo.writeFile('compare', fileName, updatedText, updatedMessage, assertSuccessful(done, function() { 360 | remoteRepo.compareBranches('master', 'compare', assertSuccessful(done, function(err, diff) { 361 | expect(diff).to.have.own('total_commits', 1); 362 | expect(diff.files[0]).to.have.own('filename', fileName); 363 | 364 | done(); 365 | })); 366 | })); 367 | })); 368 | }); 369 | 370 | it('should submit a pull request', function(done) { 371 | const base = 'master'; 372 | const head = 'pull-request'; 373 | const title = 'Test pull request'; 374 | const body = 'This is a test pull request'; 375 | const prSpec = {title, body, base, head}; 376 | 377 | remoteRepo.createBranch(base, head, assertSuccessful(done, function() { 378 | remoteRepo.writeFile(head, fileName, updatedText, updatedMessage, assertSuccessful(done, function() { 379 | remoteRepo.createPullRequest(prSpec, assertSuccessful(done, function(err, pullRequest) { 380 | expect(pullRequest).to.have.own('number'); 381 | expect(pullRequest.number).to.be.above(0); 382 | expect(pullRequest).to.have.own('title', title); 383 | expect(pullRequest).to.have.own('body', body); 384 | 385 | done(); 386 | })); 387 | })); 388 | })); 389 | }); 390 | 391 | it('should create ref on repo', function(done) { 392 | remoteRepo.getRef('heads/master', assertSuccessful(done, function(err, refSpec) { 393 | let newRef = { 394 | ref: 'refs/heads/new-test-branch', 395 | sha: refSpec.object.sha 396 | }; 397 | remoteRepo.createRef(newRef, assertSuccessful(done)); 398 | })); 399 | }); 400 | 401 | it('should delete ref on repo', function(done) { 402 | remoteRepo.deleteRef('heads/new-test-branch', assertSuccessful(done)); 403 | }); 404 | 405 | it('should list tags on repo', function(done) { 406 | remoteRepo.listTags(assertSuccessful(done)); 407 | }); 408 | 409 | it('should list pulls on repo', function(done) { 410 | const filterOpts = { 411 | state: 'all', 412 | sort: 'updated', 413 | direction: 'desc', 414 | page: 1, 415 | per_page: 10 //eslint-disable-line 416 | }; 417 | 418 | remoteRepo.listPullRequests(filterOpts, assertSuccessful(done, function(err, pullRequests) { 419 | expect(pullRequests).to.be.an.array(); 420 | expect(pullRequests).to.have.length(1); 421 | 422 | done(); 423 | })); 424 | }); 425 | 426 | it('should get pull requests on repo', function(done) { 427 | const repo = github.getRepo('michael', 'github'); 428 | 429 | repo.getPullRequest(153, assertSuccessful(done, function(err, pr) { 430 | expect(pr).to.have.own('title'); 431 | expect(pr).to.have.own('body'); 432 | expect(pr).to.have.own('url'); 433 | 434 | done(); 435 | })); 436 | }); 437 | 438 | it('should delete a file on the repo', function(done) { 439 | remoteRepo.writeFile('master', fileToDelete, initialText, deleteMessage, assertSuccessful(done, function() { 440 | remoteRepo.deleteFile('master', fileToDelete, assertSuccessful(done)); 441 | })); 442 | }); 443 | 444 | it('should write author and committer to repo', function(done) { 445 | const options = { 446 | author: {name: 'Author Name', email: 'author@example.com'}, 447 | committer: {name: 'Committer Name', email: 'committer@example.com'} 448 | }; 449 | 450 | remoteRepo.writeFile('dev', 451 | fileName, initialText, initialMessage, options, 452 | assertSuccessful(done, function(error, commit) { 453 | remoteRepo.getCommit(commit.commit.sha, assertSuccessful(done, function(err, commit2) { 454 | const author = commit2.author; 455 | const committer = commit2.committer; 456 | expect(author.name).to.be('Author Name'); 457 | expect(author.email).to.be('author@example.com'); 458 | expect(committer.name).to.be('Committer Name'); 459 | expect(committer.email).to.be('committer@example.com'); 460 | 461 | done(); 462 | })); 463 | }) 464 | ); 465 | }); 466 | 467 | it('should be able to write all the unicode', function(done) { 468 | remoteRepo.writeFile('master', unicodeFileName, unicodeText, unicodeMessage, assertSuccessful(done, 469 | function(err, commit) { 470 | expect(commit.content.name).to.be(unicodeFileName); 471 | expect(commit.commit.message).to.be(unicodeMessage); 472 | 473 | remoteRepo.getContents('master', unicodeFileName, 'raw', assertSuccessful(done, function(err, fileText) { 474 | expect(fileText).to.be(unicodeText); 475 | 476 | done(); 477 | })); 478 | })); 479 | }); 480 | 481 | it('should pass a regression test for _request (#14)', function(done) { 482 | remoteRepo.getRef('heads/master', assertSuccessful(done, function(err, refSpec) { 483 | let newRef = { 484 | ref: 'refs/heads/testing-14', 485 | sha: refSpec.object.sha 486 | }; 487 | 488 | remoteRepo.createRef(newRef, assertSuccessful(done, function() { 489 | // Triggers GET: 490 | // https://api.github.com/repos/michael/cmake_cdt7_stalled/git/refs/heads/prose-integration 491 | remoteRepo.getRef('heads/master', assertSuccessful(done, function() { 492 | // Triggers DELETE: 493 | // https://api.github.com/repos/michael/cmake_cdt7_stalled/git/refs/heads/prose-integration 494 | remoteRepo.deleteRef('heads/testing-14', assertSuccessful(done, function(err, res, xhr) { 495 | expect(xhr.status).to.be(204); 496 | 497 | done(); 498 | })); 499 | })); 500 | })); 501 | })); 502 | }); 503 | 504 | it('should be able to write an image to the repo', function(done) { 505 | const opts = { 506 | encode: false 507 | }; 508 | 509 | remoteRepo.writeFile('master', imageFileName, imageB64, initialMessage, opts, assertSuccessful(done, 510 | function(err, commit) { 511 | sha = commit.sha; 512 | 513 | done(); 514 | })); 515 | }); 516 | 517 | it('should be able to write a string blob to the repo', function(done) { 518 | remoteRepo.createBlob('String test', assertSuccessful(done)); 519 | }); 520 | 521 | it('should be able to write a file blob to the repo', function(done) { 522 | remoteRepo.createBlob(imageBlob, assertSuccessful(done)); 523 | }); 524 | 525 | it('should star the repo', function(done) { 526 | remoteRepo.star(assertSuccessful(done, function() { 527 | remoteRepo.isStarred(assertSuccessful(done)); 528 | })); 529 | }); 530 | 531 | it('should unstar the repo', function(done) { 532 | remoteRepo.unstar(assertSuccessful(done, function() { 533 | remoteRepo.isStarred(assertSuccessful(done, function(_, isStarred) { 534 | expect(isStarred).to.be(false); 535 | done(); 536 | })); 537 | })); 538 | }); 539 | 540 | it('should fail on broken commit', function(done) { 541 | remoteRepo.commit('broken-parent-hash', 'broken-tree-hash', initialMessage, assertFailure(done, function(err) { 542 | expect(err.status).to.be(422); 543 | done(); 544 | })); 545 | }); 546 | 547 | it('should create a release', function(done) { 548 | const releaseDef = { 549 | name: releaseName, 550 | tag_name: releaseTag, // eslint-disable-line 551 | target_commitish: sha // eslint-disable-line 552 | }; 553 | 554 | remoteRepo.createRelease(releaseDef, assertSuccessful(done, function(err, res) { 555 | releaseId = res.id; 556 | done(); 557 | })); 558 | }); 559 | 560 | it('should edit a release', function(done) { 561 | const releaseDef = { 562 | name: releaseName, 563 | body: releaseBody 564 | }; 565 | 566 | remoteRepo.updateRelease(releaseId, releaseDef, assertSuccessful(done, function(err, release) { 567 | expect(release).to.have.own('name', releaseName); 568 | expect(release).to.have.own('body', releaseBody); 569 | 570 | done(); 571 | })); 572 | }); 573 | 574 | it('should read all releases', function(done) { 575 | remoteRepo.listReleases(assertSuccessful(done, function(err, releases) { 576 | expect(releases).to.be.an.array(); 577 | done(); 578 | })); 579 | }); 580 | 581 | it('should read a release', function(done) { 582 | remoteRepo.getRelease(releaseId, assertSuccessful(done, function(err, release) { 583 | expect(release).to.have.own('name', releaseName); 584 | 585 | done(); 586 | })); 587 | }); 588 | 589 | it('should delete a release', function(done) { 590 | remoteRepo.deleteRelease(releaseId, assertSuccessful(done)); 591 | }); 592 | }); 593 | 594 | describe('deleting', function() { 595 | before(function() { 596 | remoteRepo = github.getRepo(testUser.USERNAME, testRepoName); 597 | }); 598 | 599 | // 200ms between tests so that Github has a chance to settle 600 | beforeEach(function(done) { 601 | setTimeout(done, 200); 602 | }); 603 | 604 | it('should delete the repo', function(done) { 605 | remoteRepo.deleteRepo(assertSuccessful(done, function(err, result) { 606 | expect(result).to.be(true); 607 | 608 | done(); 609 | })); 610 | }); 611 | }); 612 | }); 613 | -------------------------------------------------------------------------------- /test/search.spec.js: -------------------------------------------------------------------------------- 1 | import expect from 'must'; 2 | import nock from 'nock'; 3 | 4 | import Github from '../lib/GitHub'; 5 | import testUser from './fixtures/user.json'; 6 | 7 | describe('Search', function() { 8 | this.timeout(20 * 1000); 9 | let github; 10 | 11 | before(function() { 12 | github = new Github({ 13 | username: testUser.USERNAME, 14 | password: testUser.PASSWORD, 15 | auth: 'basic' 16 | }); 17 | nock.load('test/fixtures/search.json'); 18 | }); 19 | 20 | it('should search repositories', function() { 21 | let options; 22 | let search = github.search({ 23 | q: 'tetris language:assembly', 24 | sort: 'stars', 25 | order: 'desc' 26 | }); 27 | 28 | return search.forRepositories(options) 29 | .then(function({data}) { 30 | expect(data).to.be.an.array(); 31 | expect(data.length).to.be.above(0); 32 | }); 33 | }); 34 | 35 | it('should search code', function() { 36 | let options; 37 | let search = github.search({ 38 | q: 'addClass in:file language:js repo:jquery/jquery' 39 | }); 40 | 41 | return search.forCode(options) 42 | .then(function({data}) { 43 | expect(data).to.be.an.array(); 44 | expect(data.length).to.be.above(0); 45 | }); 46 | }); 47 | 48 | it('should search issues', function() { 49 | let options; 50 | let search = github.search({ 51 | q: 'windows pip label:bug language:python state:open ', 52 | sort: 'created', 53 | order: 'asc' 54 | }); 55 | 56 | return search.forIssues(options) 57 | .then(function({data}) { 58 | expect(data).to.be.an.array(); 59 | expect(data.length).to.be.above(0); 60 | }); 61 | }); 62 | 63 | it('should search users', function() { 64 | let options; 65 | let search = github.search({ 66 | q: 'tom repos:>42 followers:>1000' 67 | }); 68 | 69 | return search.forUsers(options) 70 | .then(function({data}) { 71 | expect(data).to.be.an.array(); 72 | expect(data.length).to.be.above(0); 73 | }); 74 | }); 75 | 76 | after(function() { 77 | nock.cleanAll(); 78 | nock.restore(); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /test/team.spec.js: -------------------------------------------------------------------------------- 1 | import expect from 'must'; 2 | 3 | import Github from '../lib/GitHub'; 4 | import testUser from './fixtures/user.json'; 5 | import {assertFailure} from './helpers/callbacks'; 6 | import getTestRepoName from './helpers/getTestRepoName'; 7 | 8 | const altUser = { 9 | USERNAME: 'mtscout6-test' 10 | }; 11 | 12 | function createTestTeam() { 13 | const name = getTestRepoName(); 14 | 15 | const github = new Github({ 16 | username: testUser.USERNAME, 17 | password: testUser.PASSWORD, 18 | auth: 'basic' 19 | }); 20 | 21 | const org = github.getOrganization(testUser.ORGANIZATION); 22 | 23 | return org.createTeam({ 24 | name, 25 | privacy: 'closed' 26 | }).then(({data: result}) => { 27 | const team = github.getTeam(result.id); 28 | return {team, name}; 29 | }); 30 | } 31 | 32 | let team; 33 | let name; 34 | 35 | describe('Team', function() { // Isolate tests that are based on a fixed team 36 | before(function() { 37 | const github = new Github({ 38 | username: testUser.USERNAME, 39 | password: testUser.PASSWORD, 40 | auth: 'basic' 41 | }); 42 | 43 | team = github.getTeam(2027812); // github-api-tests/fixed-test-team-1 44 | }); 45 | 46 | it('should get membership for a given user', function() { 47 | return team.getMembership(altUser.USERNAME) 48 | .then(function({data}) { 49 | expect(data.state).to.equal('active'); 50 | expect(data.role).to.equal('member'); 51 | }); 52 | }); 53 | 54 | it('should list the users in the team', function() { 55 | return team.listMembers() 56 | .then(function({data: members}) { 57 | expect(members).to.be.an.array(); 58 | 59 | let hasTestUser = members.reduce( 60 | (found, member) => member.login === testUser.USERNAME || found, 61 | false 62 | ); 63 | 64 | expect(hasTestUser).to.be.true(); 65 | }); 66 | }); 67 | 68 | it('should get team repos', function() { 69 | return team.listRepos() 70 | .then(({data}) => { 71 | const hasRepo = data.reduce( 72 | (found, repo) => repo.name === 'fixed-test-repo-1' || found, 73 | false 74 | ); 75 | 76 | expect(hasRepo).to.be.true(); 77 | }); 78 | }); 79 | 80 | it('should get team', function() { 81 | return team.getTeam() 82 | .then(({data}) => { 83 | expect(data.name).to.equal('Fixed Test Team 1'); 84 | }); 85 | }); 86 | 87 | it('should check if team manages repo', function() { 88 | return team.isManagedRepo(testUser.ORGANIZATION, 'fixed-test-repo-1') 89 | .then((result) => { 90 | expect(result).to.be.true(); 91 | }); 92 | }); 93 | }); 94 | 95 | describe('Team', function() { // Isolate tests that need a new team per test 96 | beforeEach(function() { 97 | return createTestTeam() 98 | .then((x) => { 99 | team = x.team; 100 | name = x.name; 101 | }); 102 | }); 103 | 104 | // Test for Team deletion 105 | afterEach(function(done) { 106 | team.deleteTeam() 107 | .then(() => team.getTeam(assertFailure(done))); 108 | }); 109 | 110 | it('should update team', function() { 111 | const newName = `${name}-updated`; 112 | return team.editTeam({name: newName}) 113 | .then(function({data}) { 114 | expect(data.name).to.equal(newName); 115 | }); 116 | }); 117 | 118 | it('should add membership for a given user', function() { 119 | return team.addMembership(testUser.USERNAME) 120 | .then(({data}) => { 121 | const {state, role} = data; 122 | expect(state === 'active' || state === 'pending').to.be.true(); 123 | expect(role).to.equal('member'); 124 | }); 125 | }); 126 | 127 | it('should add membership as a maintainer for a given user', function() { 128 | return team.addMembership(altUser.USERNAME, {role: 'maintainer'}) 129 | .then(({data}) => { 130 | const {state, role} = data; 131 | expect(state === 'active' || state === 'pending').to.be.true(); 132 | expect(role).to.equal('maintainer'); 133 | }); 134 | }); 135 | 136 | it('should add/remove team management of repo', function() { 137 | return team.manageRepo(testUser.ORGANIZATION, 'fixed-test-repo-1', {permission: 'pull'}) 138 | .then((result) => { 139 | expect(result).to.be.true(); 140 | return team.unmanageRepo(testUser.ORGANIZATION, 'fixed-test-repo-1'); 141 | }) 142 | .then((result) => { 143 | expect(result).to.be.true(); 144 | }); 145 | }); 146 | }); 147 | -------------------------------------------------------------------------------- /test/user.spec.js: -------------------------------------------------------------------------------- 1 | import Github from '../lib/GitHub'; 2 | import testUser from './fixtures/user.json'; 3 | import {assertSuccessful, assertArray} from './helpers/callbacks'; 4 | 5 | describe('User', function() { 6 | let github; 7 | let user; 8 | 9 | before(function() { 10 | github = new Github({ 11 | username: testUser.USERNAME, 12 | password: testUser.PASSWORD, 13 | auth: 'basic' 14 | }); 15 | user = github.getUser(); 16 | }); 17 | 18 | it('should get user repos', function(done) { 19 | user.listRepos(assertArray(done)); 20 | }); 21 | 22 | it('should get user repos with options', function(done) { 23 | const filterOpts = { 24 | type: 'owner', 25 | sort: 'updated', 26 | per_page: 90, // eslint-disable-line 27 | page: 10 28 | }; 29 | 30 | user.listRepos(filterOpts, assertArray(done)); 31 | }); 32 | 33 | it('should get user orgs', function(done) { 34 | user.listOrgs(assertArray(done)); 35 | }); 36 | 37 | it('should get user gists', function(done) { 38 | user.listGists(assertArray(done)); 39 | }); 40 | 41 | it('should get user notifications', function(done) { 42 | user.listNotifications(assertArray(done)); 43 | }); 44 | 45 | it('should get user notifications with options', function(done) { 46 | const filterOpts = { 47 | all: true, 48 | participating: true, 49 | since: '2015-01-01T00:00:00Z', 50 | before: '2015-02-01T00:00:00Z' 51 | }; 52 | 53 | user.listNotifications(filterOpts, assertArray(done)); 54 | }); 55 | 56 | it('should get the user\'s profile', function(done) { 57 | user.getProfile(assertSuccessful(done)); 58 | }); 59 | 60 | it('should show user\'s starred repos', function(done) { 61 | user.listStarredRepos(assertArray(done)); 62 | }); 63 | 64 | it('should follow user', function(done) { 65 | user.follow('ingalls', assertSuccessful(done)); 66 | }); 67 | 68 | it('should unfollow user', function(done) { 69 | user.unfollow('ingalls', assertSuccessful(done)); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /test/vendor/Blob.js: -------------------------------------------------------------------------------- 1 | /* Blob.js 2 | * A Blob implementation. 3 | * 2014-07-24 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * By Devin Samarin, https://github.com/dsamarin 7 | * License: MIT 8 | * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md 9 | */ 10 | 11 | /*global self, unescape */ 12 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 13 | plusplus: true */ 14 | 15 | /*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ 16 | 17 | (function (view) { 18 | "use strict"; 19 | 20 | view.URL = view.URL || view.webkitURL; 21 | 22 | if (view.Blob && view.URL) { 23 | try { 24 | new Blob; 25 | return; 26 | } catch (e) {} 27 | } 28 | 29 | // Internally we use a BlobBuilder implementation to base Blob off of 30 | // in order to support older browsers that only have BlobBuilder 31 | var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) { 32 | var 33 | get_class = function(object) { 34 | return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; 35 | } 36 | , FakeBlobBuilder = function BlobBuilder() { 37 | this.data = []; 38 | } 39 | , FakeBlob = function Blob(data, type, encoding) { 40 | this.data = data; 41 | this.size = data.length; 42 | this.type = type; 43 | this.encoding = encoding; 44 | } 45 | , FBB_proto = FakeBlobBuilder.prototype 46 | , FB_proto = FakeBlob.prototype 47 | , FileReaderSync = view.FileReaderSync 48 | , FileException = function(type) { 49 | this.code = this[this.name = type]; 50 | } 51 | , file_ex_codes = ( 52 | "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " 53 | + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" 54 | ).split(" ") 55 | , file_ex_code = file_ex_codes.length 56 | , real_URL = view.URL || view.webkitURL || view 57 | , real_create_object_URL = real_URL.createObjectURL 58 | , real_revoke_object_URL = real_URL.revokeObjectURL 59 | , URL = real_URL 60 | , btoa = view.btoa 61 | , atob = view.atob 62 | 63 | , ArrayBuffer = view.ArrayBuffer 64 | , Uint8Array = view.Uint8Array 65 | 66 | , origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/ 67 | ; 68 | FakeBlob.fake = FB_proto.fake = true; 69 | while (file_ex_code--) { 70 | FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; 71 | } 72 | // Polyfill URL 73 | if (!real_URL.createObjectURL) { 74 | URL = view.URL = function(uri) { 75 | var 76 | uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a") 77 | , uri_origin 78 | ; 79 | uri_info.href = uri; 80 | if (!("origin" in uri_info)) { 81 | if (uri_info.protocol.toLowerCase() === "data:") { 82 | uri_info.origin = null; 83 | } else { 84 | uri_origin = uri.match(origin); 85 | uri_info.origin = uri_origin && uri_origin[1]; 86 | } 87 | } 88 | return uri_info; 89 | }; 90 | } 91 | URL.createObjectURL = function(blob) { 92 | var 93 | type = blob.type 94 | , data_URI_header 95 | ; 96 | if (type === null) { 97 | type = "application/octet-stream"; 98 | } 99 | if (blob instanceof FakeBlob) { 100 | data_URI_header = "data:" + type; 101 | if (blob.encoding === "base64") { 102 | return data_URI_header + ";base64," + blob.data; 103 | } else if (blob.encoding === "URI") { 104 | return data_URI_header + "," + decodeURIComponent(blob.data); 105 | } if (btoa) { 106 | return data_URI_header + ";base64," + btoa(blob.data); 107 | } else { 108 | return data_URI_header + "," + encodeURIComponent(blob.data); 109 | } 110 | } else if (real_create_object_URL) { 111 | return real_create_object_URL.call(real_URL, blob); 112 | } 113 | }; 114 | URL.revokeObjectURL = function(object_URL) { 115 | if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { 116 | real_revoke_object_URL.call(real_URL, object_URL); 117 | } 118 | }; 119 | FBB_proto.append = function(data/*, endings*/) { 120 | var bb = this.data; 121 | // decode data to a binary string 122 | if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { 123 | var 124 | str = "" 125 | , buf = new Uint8Array(data) 126 | , i = 0 127 | , buf_len = buf.length 128 | ; 129 | for (; i < buf_len; i++) { 130 | str += String.fromCharCode(buf[i]); 131 | } 132 | bb.push(str); 133 | } else if (get_class(data) === "Blob" || get_class(data) === "File") { 134 | if (FileReaderSync) { 135 | var fr = new FileReaderSync; 136 | bb.push(fr.readAsBinaryString(data)); 137 | } else { 138 | // async FileReader won't work as BlobBuilder is sync 139 | throw new FileException("NOT_READABLE_ERR"); 140 | } 141 | } else if (data instanceof FakeBlob) { 142 | if (data.encoding === "base64" && atob) { 143 | bb.push(atob(data.data)); 144 | } else if (data.encoding === "URI") { 145 | bb.push(decodeURIComponent(data.data)); 146 | } else if (data.encoding === "raw") { 147 | bb.push(data.data); 148 | } 149 | } else { 150 | if (typeof data !== "string") { 151 | data += ""; // convert unsupported types to strings 152 | } 153 | // decode UTF-16 to binary string 154 | bb.push(unescape(encodeURIComponent(data))); 155 | } 156 | }; 157 | FBB_proto.getBlob = function(type) { 158 | if (!arguments.length) { 159 | type = null; 160 | } 161 | return new FakeBlob(this.data.join(""), type, "raw"); 162 | }; 163 | FBB_proto.toString = function() { 164 | return "[object BlobBuilder]"; 165 | }; 166 | FB_proto.slice = function(start, end, type) { 167 | var args = arguments.length; 168 | if (args < 3) { 169 | type = null; 170 | } 171 | return new FakeBlob( 172 | this.data.slice(start, args > 1 ? end : this.data.length) 173 | , type 174 | , this.encoding 175 | ); 176 | }; 177 | FB_proto.toString = function() { 178 | return "[object Blob]"; 179 | }; 180 | FB_proto.close = function() { 181 | this.size = 0; 182 | delete this.data; 183 | }; 184 | return FakeBlobBuilder; 185 | }(view)); 186 | 187 | view.Blob = function(blobParts, options) { 188 | var type = options ? (options.type || "") : ""; 189 | var builder = new BlobBuilder(); 190 | if (blobParts) { 191 | for (var i = 0, len = blobParts.length; i < len; i++) { 192 | if (Uint8Array && blobParts[i] instanceof Uint8Array) { 193 | builder.append(blobParts[i].buffer); 194 | } 195 | else { 196 | builder.append(blobParts[i]); 197 | } 198 | } 199 | } 200 | var blob = builder.getBlob(type); 201 | if (!blob.slice && blob.webkitSlice) { 202 | blob.slice = blob.webkitSlice; 203 | } 204 | return blob; 205 | }; 206 | 207 | var getPrototypeOf = Object.getPrototypeOf || function(object) { 208 | return object.__proto__; 209 | }; 210 | view.Blob.prototype = getPrototypeOf(new view.Blob()); 211 | }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this)); 212 | --------------------------------------------------------------------------------