Skip to content

Commit 0f0a251

Browse files
authored
Fix race conditions and add tests (#85)
* Fix race conditions and add tests * Move to main branch * Publish to "main" dist tag * Add entry
1 parent 2780945 commit 0f0a251

File tree

103 files changed

+70441
-7120
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+70441
-7120
lines changed

.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/*
2+
!/__tests__
3+
!/Dockerfile
4+
!/packages/component/dist/*

.github/workflows/node.js.yml

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,66 +6,85 @@ name: Node.js CI
66
on:
77
push:
88
branches:
9-
- master
9+
- main
1010
tags:
1111
- '*'
1212

1313
pull_request:
1414
branches:
15-
- master
15+
- main
1616

1717
jobs:
1818
build:
1919
runs-on: ubuntu-latest
2020

2121
strategy:
2222
matrix:
23-
node-version: [12.x, 14.x]
23+
node-version: [14.x, 16.x]
2424

2525
steps:
2626
- name: Checking out for ${{ github.ref }}
2727
uses: actions/checkout@v2
2828

29-
- name: Use Node.js ${{ matrix.node-version }}
29+
- name: Using Node.js ${{ matrix.node-version }}
3030
uses: actions/setup-node@v1
3131
with:
3232
node-version: ${{ matrix.node-version }}
3333

34-
- name: Run npx version-from-git --no-git-tag-version
34+
- name: Running npx version-from-git --no-git-tag-version
3535
if: ${{ startsWith(github.ref, 'refs/heads/') }}
3636
run: npx version-from-git --no-git-tag-version
3737

38-
- run: npm ci
38+
- name: Installing dependencies
39+
run: npm ci
3940

40-
- run: npm run bootstrap
41+
- name: Bootstrapping packages
42+
run: npm run bootstrap
4143

42-
- name: Propagate versions
44+
- name: Propagating versions
4345
run: |
4446
node_modules/.bin/lerna version --force-publish --no-git-tag-version --no-push --yes `cat package.json | jq -r .version`
4547
46-
- run: npm run build --if-present
48+
- name: Building for instrumentation
49+
env:
50+
NODE_ENV: test
51+
SKIP_PREFLIGHT_CHECK: 'true'
52+
run: npm run build --if-present
53+
54+
- name: Starting Docker Compose
55+
run: npm run docker:up -- --detach
56+
57+
- name: Testing
58+
run: npm test -- --coverage
4759

48-
- run: npm test
60+
- name: Stopping Docker Compose
61+
run: npm run docker:down
62+
63+
- name: Building for production
64+
env:
65+
NODE_ENV: production
66+
SKIP_PREFLIGHT_CHECK: 'true'
67+
run: npm run build --if-present
4968

50-
- name: Copy documents
69+
- name: Copying documents
5170
run: |
5271
cp CHANGELOG.md packages/component
5372
cp LICENSE packages/component
5473
cp README.md packages/component
5574
56-
- name: Run npm pack
75+
- name: Running npm pack
5776
run: |
5877
cd packages/component
5978
npm pack
6079
61-
- name: Upload npm-tarball
80+
- name: Uploading npm-tarball
6281
uses: actions/upload-artifact@v2
6382
if: ${{ matrix.node-version == '14.x' }}
6483
with:
6584
name: npm-tarball
6685
path: 'packages/component/*.tgz'
6786

68-
- name: Upload gh-pages
87+
- name: Uploading gh-pages
6988
uses: actions/upload-artifact@v2
7089
if: ${{ matrix.node-version == '14.x' }}
7190
with:
@@ -78,36 +97,36 @@ jobs:
7897
if: ${{ startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/') }}
7998

8099
steps:
81-
- name: Download npm-tarball
100+
- name: Downloading npm-tarball
82101
uses: actions/download-artifact@v2
83102
with:
84103
name: npm-tarball
85104

86-
- name: Download gh-pages
105+
- name: Downloading gh-pages
87106
uses: actions/download-artifact@v2
88107
with:
89108
name: gh-pages
90109
path: gh-pages/
91110

92-
- name: Read package.json
111+
- name: Reading package.json
93112
id: read-package-json
94113
run: |
95114
echo "::set-output name=name::$(tar xOf *.tgz package/package.json | jq -r '.name')"
96115
echo "::set-output name=version::$(tar xOf *.tgz package/package.json | jq -r '.version')"
97116
echo "::set-output name=tarball::$(ls *.tgz)"
98117
echo "::set-output name=date::$(date +%Y-%m-%d)"
99118
100-
- name: Run npm publish ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }}
119+
- name: Publishing ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }}
101120
run: |
102121
npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
103-
npm publish *.tgz --tag master
122+
npm publish *.tgz --tag main
104123
105-
- name: Run npm dist-tag add ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }} latest
124+
- name: Tagging dist-tag ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }} latest
106125
if: ${{ startsWith(github.ref, 'refs/tags/') }}
107126
run: |
108127
npm dist-tag add ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }} latest
109128
110-
- name: Draft a new release
129+
- name: Drafting a new release
111130
uses: actions/create-release@v1
112131
id: create-release
113132
if: ${{ startsWith(github.ref, 'refs/tags/') }}
@@ -118,7 +137,7 @@ jobs:
118137
release_name: '[${{ steps.read-package-json.outputs.version }}] - ${{ steps.read-package-json.outputs.date }}'
119138
draft: true
120139

121-
- name: Upload tarball to release
140+
- name: Uploading tarball to release
122141
uses: actions/upload-release-asset@v1
123142
if: ${{ startsWith(github.ref, 'refs/tags/') }}
124143
env:
@@ -129,7 +148,7 @@ jobs:
129148
asset_name: ${{ steps.read-package-json.outputs.tarball }}
130149
asset_content_type: application/octet-stream
131150

132-
- name: Deploy to GitHub Pages
151+
- name: Deploying to GitHub Pages
133152
uses: peaceiris/actions-gh-pages@v3
134153
with:
135154
github_token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/.env
2+
/chromedriver*
3+
/coverage
14
/lerna-debug.log
25
/lib
36
/node_modules

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Added a test harness, in PR [#85](https://github.com/compulim/react-scroll-to-bottom/pull/85)
13+
1014
### Fixed
1115

1216
- Fixed [#75](https://github.com/compulim/react-scroll-to-bottom/issues/75). If `debug` is set, it will show debug in console log. If not specified, it will fallback to `NODE_ENV === 'production'`, in PR [#77](https://github.com/compulim/react-scroll-to-bottom/pull/77).
17+
- Fixed [#84](https://github.com/compulim/react-scroll-to-bottom/issues/84). Fixed a race condition: while under heavy load, sticky, and at the end, calling `useScrollTo()` to any positions, the scroll view may scroll back to the bottom immediately, in PR [#85](https://github.com/compulim/react-scroll-to-bottom/pull/85)
1318

1419
## [4.1.0] - 2021-01-03
1520

Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM node:alpine
2+
3+
EXPOSE 80
4+
RUN npm install serve -g
5+
WORKDIR /var/web/
6+
ENTRYPOINT ["npx", "--no-install", "serve", "-c", "serve.json", "-p", "80", "/var/web/"]
7+
8+
RUN echo {}>/var/web/package.json
9+
10+
ADD __tests__/*.html /var/web/
11+
ADD __tests__/assets/ /var/web/assets/
12+
ADD __tests__/favicon.ico /var/web/
13+
ADD __tests__/serve.json /var/web/
14+
ADD packages/component/dist/ /var/web/

__tests__/assets/index.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
body,
2+
html {
3+
height: 100%;
4+
}
5+
6+
body {
7+
align-items: center;
8+
background: #f7f7f7;
9+
display: flex;
10+
justify-content: center;
11+
margin: 0;
12+
}
13+
14+
.react-scroll-to-bottom {
15+
background: White;
16+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
17+
height: 640px;
18+
width: 360px;
19+
}

__tests__/assets/page-object-model.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
class PageObjects {
2+
async mouseWheel(deltaY) {
3+
const scrollable = document.getElementsByClassName('scrollable')[0];
4+
const { height, left, top, width } = scrollable.getBoundingClientRect();
5+
6+
await webDriver.sendDevToolsCommand('Input.dispatchMouseEvent', {
7+
deltaX: 0,
8+
deltaY,
9+
type: 'mouseWheel',
10+
x: left + width / 2,
11+
y: top + height / 2
12+
});
13+
}
14+
15+
paragraphs = [
16+
'Tempor id consectetur ex non irure aliquip ea irure sint voluptate et. Magna aute reprehenderit amet dolor laboris. Adipisicing aliqua officia tempor magna aliqua commodo proident.',
17+
'Ad aute esse dolor in veniam reprehenderit labore et. Et dolor sint proident dolor. Aliquip amet duis laboris laboris dolor proident sit adipisicing enim dolore elit dolore.',
18+
'Consectetur irure qui excepteur voluptate et exercitation. Nostrud sint officia ipsum qui duis do. Amet veniam ipsum tempor anim ad voluptate commodo quis exercitation. Consectetur et laborum Lorem cillum aliquip quis duis est officia culpa consequat nostrud ex. Officia dolore mollit irure aliquip aliquip minim dolor eiusmod et magna.',
19+
'Proident aliquip culpa aliquip esse cupidatat incididunt voluptate pariatur ullamco ea aute cupidatat. Ex fugiat mollit sunt duis elit aliqua cupidatat officia. Laborum magna dolor non ea aliquip tempor. Sunt voluptate sint minim elit eu eiusmod. Dolor nisi qui enim excepteur ut non elit enim deserunt consectetur in quis. Aute et incididunt sunt est do.',
20+
'Cillum qui adipisicing culpa laborum eu. Amet qui duis sunt qui magna fugiat culpa. Sit ea amet do sint.',
21+
'Laboris nulla esse duis fugiat mollit duis consequat incididunt anim eiusmod. Esse labore eiusmod sint culpa Lorem in cupidatat duis. Do et proident irure commodo ut ut reprehenderit ut esse deserunt minim occaecat sunt. Consequat in elit amet labore quis deserunt.',
22+
'Tempor esse enim cupidatat tempor amet. Sint esse ad consectetur quis minim aliquip. Eiusmod consectetur tempor occaecat deserunt officia enim tempor anim incididunt. Irure duis ad laboris anim. Ullamco reprehenderit voluptate adipisicing excepteur duis id magna quis ex aliqua minim magna minim occaecat.',
23+
'In consequat ea irure officia enim adipisicing. Laboris excepteur incididunt ad in. Dolor mollit occaecat sunt elit minim commodo est incididunt sit reprehenderit commodo. Sit magna duis minim elit irure velit culpa dolor. Minim culpa nisi et fugiat. In est dolore anim sunt est minim qui sunt mollit commodo id qui non duis. Commodo occaecat occaecat eu cupidatat nostrud nulla ad mollit reprehenderit.',
24+
'Adipisicing ex sint adipisicing irure ut consectetur nisi consectetur enim qui cillum nostrud. Ullamco adipisicing excepteur proident qui amet eiusmod aute Lorem voluptate eiusmod ullamco. Ex non laborum incididunt nulla ad.'
25+
];
26+
27+
async scrollStabilized() {
28+
await stabilized('scroll', () => document.getElementsByClassName('scrollable')[0].scrollTop, 5, 5000);
29+
}
30+
31+
async scrollStabilizedAt(message, offset) {
32+
await stabilized(
33+
message,
34+
() => {
35+
const scrollable = document.getElementsByClassName('scrollable')[0];
36+
37+
return Math.abs(scrollable.scrollTop - offset) <= 1 ? scrollable.scrollTop : {};
38+
},
39+
5,
40+
5000
41+
);
42+
}
43+
44+
async scrollStabilizedAtBottom() {
45+
const scrollable = document.getElementsByClassName('scrollable')[0];
46+
47+
await this.scrollStabilizedAt('scroll is at bottom', scrollable.scrollHeight - scrollable.clientHeight);
48+
}
49+
50+
async scrollStabilizedAtTop() {
51+
await this.scrollStabilizedAt('scroll is at top', 0);
52+
}
53+
}
54+
55+
window.pageObjects || (window.pageObjects = new PageObjects());
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title></title>
5+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
6+
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
7+
<script src="/react-scroll-to-bottom.development.js"></script>
8+
<script src="/test-harness.js"></script>
9+
<script src="/assets/page-object-model.js"></script>
10+
</head>
11+
<body>
12+
<div id="app"></div>
13+
</body>
14+
<script type="text/babel" data-presets="react">
15+
'use strict';
16+
17+
run(async function () {
18+
await new Promise(resolve =>
19+
ReactDOM.render(
20+
<ReactScrollToBottom.default
21+
className="react-scroll-to-bottom"
22+
followButtonClassName="follow"
23+
scrollViewClassName="scrollable"
24+
>
25+
{pageObjects.paragraphs.map(paragraph => (
26+
<p key={paragraph}>{paragraph}</p>
27+
))}
28+
</ReactScrollToBottom.default>,
29+
document.getElementById('app'),
30+
resolve
31+
)
32+
);
33+
34+
await pageObjects.scrollStabilizedAtBottom();
35+
36+
expect(document.getElementsByClassName('follow')[0]).toBeFalsy();
37+
38+
await pageObjects.mouseWheel(-100);
39+
40+
await pageObjects.scrollStabilized();
41+
42+
await webDriver.click(document.getElementsByClassName('follow')[0]);
43+
44+
await pageObjects.scrollStabilized();
45+
});
46+
</script>
47+
</html>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/** @jest-environment ./packages/test-harness/JestEnvironment */
2+
3+
test('click follow button should scroll to bottom', () => runHTML('click-follow-button-should-scroll-to-bottom.html'));

__tests__/favicon.ico

119 Bytes
Binary file not shown.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title></title>
5+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
6+
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
7+
<script src="/react-scroll-to-bottom.development.js"></script>
8+
<script src="/test-harness.js"></script>
9+
<script src="/assets/page-object-model.js"></script>
10+
</head>
11+
<body>
12+
<div id="app"></div>
13+
</body>
14+
<script type="text/babel" data-presets="react">
15+
'use strict';
16+
17+
run(async function () {
18+
await new Promise(resolve =>
19+
ReactDOM.render(
20+
<ReactScrollToBottom.default
21+
className="react-scroll-to-bottom"
22+
followButtonClassName="follow"
23+
scrollViewClassName="scrollable"
24+
>
25+
{pageObjects.paragraphs.map(paragraph => (
26+
<p key={paragraph}>{paragraph}</p>
27+
))}
28+
</ReactScrollToBottom.default>,
29+
document.getElementById('app'),
30+
resolve
31+
)
32+
);
33+
34+
await pageObjects.scrollStabilizedAtBottom();
35+
36+
expect(document.getElementsByClassName('follow')[0]).toBeFalsy();
37+
38+
await pageObjects.mouseWheel(-100);
39+
40+
await pageObjects.scrollStabilized();
41+
42+
expect(document.getElementsByClassName('follow')[0]).toBeTruthy();
43+
});
44+
</script>
45+
</html>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/** @jest-environment ./packages/test-harness/JestEnvironment */
2+
3+
test('scroll up should show follow button', () => runHTML('scroll-up-should-show-follow-button.html'));

0 commit comments

Comments
 (0)