Skip to content

Commit

Permalink
Fix race conditions and add tests (#85)
Browse files Browse the repository at this point in the history
* Fix race conditions and add tests

* Move to main branch

* Publish to "main" dist tag

* Add entry
  • Loading branch information
compulim authored May 13, 2021
1 parent 2780945 commit 0f0a251
Show file tree
Hide file tree
Showing 103 changed files with 70,441 additions and 7,120 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
!/__tests__
!/Dockerfile
!/packages/component/dist/*
65 changes: 42 additions & 23 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,66 +6,85 @@ name: Node.js CI
on:
push:
branches:
- master
- main
tags:
- '*'

pull_request:
branches:
- master
- main

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [12.x, 14.x]
node-version: [14.x, 16.x]

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

- name: Use Node.js ${{ matrix.node-version }}
- name: Using Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

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

- run: npm ci
- name: Installing dependencies
run: npm ci

- run: npm run bootstrap
- name: Bootstrapping packages
run: npm run bootstrap

- name: Propagate versions
- name: Propagating versions
run: |
node_modules/.bin/lerna version --force-publish --no-git-tag-version --no-push --yes `cat package.json | jq -r .version`
- run: npm run build --if-present
- name: Building for instrumentation
env:
NODE_ENV: test
SKIP_PREFLIGHT_CHECK: 'true'
run: npm run build --if-present

- name: Starting Docker Compose
run: npm run docker:up -- --detach

- name: Testing
run: npm test -- --coverage

- run: npm test
- name: Stopping Docker Compose
run: npm run docker:down

- name: Building for production
env:
NODE_ENV: production
SKIP_PREFLIGHT_CHECK: 'true'
run: npm run build --if-present

- name: Copy documents
- name: Copying documents
run: |
cp CHANGELOG.md packages/component
cp LICENSE packages/component
cp README.md packages/component
- name: Run npm pack
- name: Running npm pack
run: |
cd packages/component
npm pack
- name: Upload npm-tarball
- name: Uploading npm-tarball
uses: actions/upload-artifact@v2
if: ${{ matrix.node-version == '14.x' }}
with:
name: npm-tarball
path: 'packages/component/*.tgz'

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

steps:
- name: Download npm-tarball
- name: Downloading npm-tarball
uses: actions/download-artifact@v2
with:
name: npm-tarball

- name: Download gh-pages
- name: Downloading gh-pages
uses: actions/download-artifact@v2
with:
name: gh-pages
path: gh-pages/

- name: Read package.json
- name: Reading package.json
id: read-package-json
run: |
echo "::set-output name=name::$(tar xOf *.tgz package/package.json | jq -r '.name')"
echo "::set-output name=version::$(tar xOf *.tgz package/package.json | jq -r '.version')"
echo "::set-output name=tarball::$(ls *.tgz)"
echo "::set-output name=date::$(date +%Y-%m-%d)"
- name: Run npm publish ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }}
- name: Publishing ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }}
run: |
npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
npm publish *.tgz --tag master
npm publish *.tgz --tag main
- name: Run npm dist-tag add ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }} latest
- name: Tagging dist-tag ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }} latest
if: ${{ startsWith(github.ref, 'refs/tags/') }}
run: |
npm dist-tag add ${{ steps.read-package-json.outputs.name }}@${{ steps.read-package-json.outputs.version }} latest
- name: Draft a new release
- name: Drafting a new release
uses: actions/create-release@v1
id: create-release
if: ${{ startsWith(github.ref, 'refs/tags/') }}
Expand All @@ -118,7 +137,7 @@ jobs:
release_name: '[${{ steps.read-package-json.outputs.version }}] - ${{ steps.read-package-json.outputs.date }}'
draft: true

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

- name: Deploy to GitHub Pages
- name: Deploying to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/.env
/chromedriver*
/coverage
/lerna-debug.log
/lib
/node_modules
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added

- Added a test harness, in PR [#85](https://github.com/compulim/react-scroll-to-bottom/pull/85)

### Fixed

- 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).
- 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)

## [4.1.0] - 2021-01-03

Expand Down
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:alpine

EXPOSE 80
RUN npm install serve -g
WORKDIR /var/web/
ENTRYPOINT ["npx", "--no-install", "serve", "-c", "serve.json", "-p", "80", "/var/web/"]

RUN echo {}>/var/web/package.json

ADD __tests__/*.html /var/web/
ADD __tests__/assets/ /var/web/assets/
ADD __tests__/favicon.ico /var/web/
ADD __tests__/serve.json /var/web/
ADD packages/component/dist/ /var/web/
19 changes: 19 additions & 0 deletions __tests__/assets/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
body,
html {
height: 100%;
}

body {
align-items: center;
background: #f7f7f7;
display: flex;
justify-content: center;
margin: 0;
}

.react-scroll-to-bottom {
background: White;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
height: 640px;
width: 360px;
}
55 changes: 55 additions & 0 deletions __tests__/assets/page-object-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
class PageObjects {
async mouseWheel(deltaY) {
const scrollable = document.getElementsByClassName('scrollable')[0];
const { height, left, top, width } = scrollable.getBoundingClientRect();

await webDriver.sendDevToolsCommand('Input.dispatchMouseEvent', {
deltaX: 0,
deltaY,
type: 'mouseWheel',
x: left + width / 2,
y: top + height / 2
});
}

paragraphs = [
'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.',
'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.',
'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.',
'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.',
'Cillum qui adipisicing culpa laborum eu. Amet qui duis sunt qui magna fugiat culpa. Sit ea amet do sint.',
'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.',
'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.',
'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.',
'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.'
];

async scrollStabilized() {
await stabilized('scroll', () => document.getElementsByClassName('scrollable')[0].scrollTop, 5, 5000);
}

async scrollStabilizedAt(message, offset) {
await stabilized(
message,
() => {
const scrollable = document.getElementsByClassName('scrollable')[0];

return Math.abs(scrollable.scrollTop - offset) <= 1 ? scrollable.scrollTop : {};
},
5,
5000
);
}

async scrollStabilizedAtBottom() {
const scrollable = document.getElementsByClassName('scrollable')[0];

await this.scrollStabilizedAt('scroll is at bottom', scrollable.scrollHeight - scrollable.clientHeight);
}

async scrollStabilizedAtTop() {
await this.scrollStabilizedAt('scroll is at top', 0);
}
}

window.pageObjects || (window.pageObjects = new PageObjects());
47 changes: 47 additions & 0 deletions __tests__/click-follow-button-should-scroll-to-bottom.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="/react-scroll-to-bottom.development.js"></script>
<script src="/test-harness.js"></script>
<script src="/assets/page-object-model.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script type="text/babel" data-presets="react">
'use strict';

run(async function () {
await new Promise(resolve =>
ReactDOM.render(
<ReactScrollToBottom.default
className="react-scroll-to-bottom"
followButtonClassName="follow"
scrollViewClassName="scrollable"
>
{pageObjects.paragraphs.map(paragraph => (
<p key={paragraph}>{paragraph}</p>
))}
</ReactScrollToBottom.default>,
document.getElementById('app'),
resolve
)
);

await pageObjects.scrollStabilizedAtBottom();

expect(document.getElementsByClassName('follow')[0]).toBeFalsy();

await pageObjects.mouseWheel(-100);

await pageObjects.scrollStabilized();

await webDriver.click(document.getElementsByClassName('follow')[0]);

await pageObjects.scrollStabilized();
});
</script>
</html>
3 changes: 3 additions & 0 deletions __tests__/click-follow-button-should-scroll-to-bottom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/** @jest-environment ./packages/test-harness/JestEnvironment */

test('click follow button should scroll to bottom', () => runHTML('click-follow-button-should-scroll-to-bottom.html'));
Binary file added __tests__/favicon.ico
Binary file not shown.
45 changes: 45 additions & 0 deletions __tests__/scroll-up-should-show-follow-button.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="/react-scroll-to-bottom.development.js"></script>
<script src="/test-harness.js"></script>
<script src="/assets/page-object-model.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script type="text/babel" data-presets="react">
'use strict';

run(async function () {
await new Promise(resolve =>
ReactDOM.render(
<ReactScrollToBottom.default
className="react-scroll-to-bottom"
followButtonClassName="follow"
scrollViewClassName="scrollable"
>
{pageObjects.paragraphs.map(paragraph => (
<p key={paragraph}>{paragraph}</p>
))}
</ReactScrollToBottom.default>,
document.getElementById('app'),
resolve
)
);

await pageObjects.scrollStabilizedAtBottom();

expect(document.getElementsByClassName('follow')[0]).toBeFalsy();

await pageObjects.mouseWheel(-100);

await pageObjects.scrollStabilized();

expect(document.getElementsByClassName('follow')[0]).toBeTruthy();
});
</script>
</html>
3 changes: 3 additions & 0 deletions __tests__/scroll-up-should-show-follow-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/** @jest-environment ./packages/test-harness/JestEnvironment */

test('scroll up should show follow button', () => runHTML('scroll-up-should-show-follow-button.html'));
Loading

0 comments on commit 0f0a251

Please sign in to comment.