Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.

Commit ac0db9c

Browse files
committed
Drive the Refresher in GitHubTabContainer
1 parent 63cb0ea commit ac0db9c

File tree

2 files changed

+98
-21
lines changed

2 files changed

+98
-21
lines changed

lib/containers/github-tab-container.js

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33
import yubikiri from 'yubikiri';
4+
import {CompositeDisposable, Disposable} from 'event-kit';
45

56
import {GithubLoginModelPropType, RefHolderPropType} from '../prop-types';
67
import OperationStateObserver, {PUSH, PULL, FETCH} from '../models/operation-state-observer';
8+
import Refresher from '../models/refresher';
79
import GitHubTabController from '../controllers/github-tab-controller';
810
import ObserveModel from '../views/observe-model';
911
import RemoteSet from '../models/remote-set';
@@ -25,19 +27,41 @@ export default class GitHubTabContainer extends React.Component {
2527
openGitTab: PropTypes.func.isRequired,
2628
}
2729

28-
state = {};
30+
constructor(props) {
31+
super(props);
32+
33+
this.state = {
34+
lastRepository: null,
35+
remoteOperationObserver: new Disposable(),
36+
refresher: new Refresher(),
37+
observerSub: new Disposable(),
38+
};
39+
}
2940

3041
static getDerivedStateFromProps(props, state) {
3142
if (props.repository !== state.lastRepository) {
43+
state.remoteOperationObserver.dispose();
44+
state.observerSub.dispose();
45+
46+
const remoteOperationObserver = new OperationStateObserver(props.repository, PUSH, PULL, FETCH);
47+
const observerSub = remoteOperationObserver.onDidComplete(() => state.refresher.trigger());
48+
3249
return {
3350
lastRepository: props.repository,
34-
remoteOperationObserver: new OperationStateObserver(props.repository, PUSH, PULL, FETCH),
51+
remoteOperationObserver,
52+
observerSub,
3553
};
3654
}
3755

3856
return null;
3957
}
4058

59+
componentWillUnmount() {
60+
this.state.observerSub.dispose();
61+
this.state.remoteOperationObserver.dispose();
62+
this.state.refresher.dispose();
63+
}
64+
4165
fetchRepositoryData = repository => {
4266
return yubikiri({
4367
workingDirectory: repository.getWorkingDirectoryPath(),
@@ -66,6 +90,7 @@ export default class GitHubTabContainer extends React.Component {
6690
return (
6791
<GitHubTabController
6892
{...this.props}
93+
refresher={this.state.refresher}
6994
remoteOperationObserver={this.state.remoteOperationObserver}
7095

7196
allRemotes={new RemoteSet()}
@@ -81,6 +106,7 @@ export default class GitHubTabContainer extends React.Component {
81106
return (
82107
<GitHubTabController
83108
{...this.props}
109+
refresher={this.state.refresher}
84110
remoteOperationObserver={this.state.remoteOperationObserver}
85111

86112
allRemotes={new RemoteSet()}
@@ -96,6 +122,7 @@ export default class GitHubTabContainer extends React.Component {
96122
<GitHubTabController
97123
{...data}
98124
{...this.props}
125+
refresher={this.state.refresher}
99126
remoteOperationObserver={this.state.remoteOperationObserver}
100127
isLoading={false}
101128
/>

test/containers/github-tab-container.test.js

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
import React from 'react';
2-
import {mount} from 'enzyme';
2+
import {mount, shallow} from 'enzyme';
33

4-
import {cloneRepository} from '../helpers';
4+
import {buildRepository, cloneRepository} from '../helpers';
55
import GitHubTabContainer from '../../lib/containers/github-tab-container';
6+
import GitHubTabController from '../../lib/controllers/github-tab-controller';
67
import Repository from '../../lib/models/repository';
78
import {InMemoryStrategy} from '../../lib/shared/keytar-strategy';
89
import GithubLoginModel from '../../lib/models/github-login-model';
910
import RefHolder from '../../lib/models/ref-holder';
1011

1112
describe('GitHubTabContainer', function() {
12-
let atomEnv, repository;
13+
let atomEnv, repository, defaultRepositoryData;
1314

14-
beforeEach(function() {
15+
beforeEach(async function() {
1516
atomEnv = global.buildAtomEnvironment();
16-
repository = Repository.absent();
17+
repository = await buildRepository(await cloneRepository());
18+
19+
defaultRepositoryData = {
20+
workingDirectory: repository.getWorkingDirectoryPath(),
21+
allRemotes: await repository.getRemotes(),
22+
branches: await repository.getBranches(),
23+
selectedRemoteName: 'origin',
24+
aheadCount: 0,
25+
pushInProgress: false,
26+
};
1727
});
1828

1929
afterEach(function() {
@@ -41,26 +51,66 @@ describe('GitHubTabContainer', function() {
4151
);
4252
}
4353

44-
describe('operation state observer', function() {
45-
it('creates an observer on the current repository', function() {
46-
const wrapper = mount(buildApp());
54+
describe('refresher', function() {
55+
let wrapper, retry;
56+
57+
function stubRepository(repo) {
58+
sinon.stub(repo.getOperationStates(), 'isFetchInProgress').returns(false);
59+
sinon.stub(repo.getOperationStates(), 'isPushInProgress').returns(false);
60+
sinon.stub(repo.getOperationStates(), 'isPullInProgress').returns(false);
61+
}
62+
63+
function simulateOperation(repo, name, middle = () => {}) {
64+
const accessor = `is${name[0].toUpperCase()}${name.slice(1)}InProgress`;
65+
const methodStub = repo.getOperationStates()[accessor];
66+
methodStub.returns(true);
67+
repo.state.didUpdate();
68+
middle();
69+
methodStub.returns(false);
70+
repo.state.didUpdate();
71+
}
72+
73+
beforeEach(function() {
74+
wrapper = shallow(buildApp());
75+
const childWrapper = wrapper.find('ObserveModel').renderProp('children')(defaultRepositoryData);
76+
77+
retry = sinon.spy();
78+
const refresher = childWrapper.find(GitHubTabController).prop('refresher');
79+
refresher.setRetryCallback(Symbol('key'), retry);
80+
81+
stubRepository(repository);
82+
});
83+
84+
it('triggers a refresh when the current repository completes a fetch, push, or pull', function() {
85+
assert.isFalse(retry.called);
86+
87+
simulateOperation(repository, 'fetch', () => assert.isFalse(retry.called));
88+
assert.strictEqual(retry.callCount, 1);
4789

48-
const observer = wrapper.state('remoteOperationObserver');
49-
assert.strictEqual(observer.repository, repository);
90+
simulateOperation(repository, 'push', () => assert.strictEqual(retry.callCount, 1));
91+
assert.strictEqual(retry.callCount, 2);
5092

51-
wrapper.setProps({});
52-
assert.strictEqual(wrapper.state('remoteOperationObserver'), observer);
93+
simulateOperation(repository, 'pull', () => assert.strictEqual(retry.callCount, 2));
94+
assert.strictEqual(retry.callCount, 3);
5395
});
5496

55-
it('creates a new observer when the repository changes', function() {
56-
const repository0 = Repository.absent();
57-
const wrapper = mount(buildApp({repository: repository0}));
97+
it('un-observes an old repository and observes a new one', async function() {
98+
const other = await buildRepository(await cloneRepository());
99+
stubRepository(other);
100+
wrapper.setProps({repository: other});
101+
102+
simulateOperation(repository, 'fetch');
103+
assert.isFalse(retry.called);
104+
105+
simulateOperation(other, 'fetch');
106+
assert.isTrue(retry.called);
107+
});
58108

59-
const observer0 = wrapper.state('remoteOperationObserver');
109+
it('un-observes the repository when unmounting', function() {
110+
wrapper.unmount();
60111

61-
const repository1 = Repository.absent();
62-
wrapper.setProps({repository: repository1});
63-
assert.notStrictEqual(wrapper.state('remoteOperationObserver'), observer0);
112+
simulateOperation(repository, 'fetch');
113+
assert.isFalse(retry.called);
64114
});
65115
});
66116

0 commit comments

Comments
 (0)