mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-27 17:45:52 -05:00
Merge pull request #4551 from LLK/release/2020-10-22
[Master] Release/2020-10-22
This commit is contained in:
commit
d53ae21757
27 changed files with 1984 additions and 1915 deletions
|
@ -48,6 +48,11 @@ env:
|
|||
- PROJECT_HOST_VAR=PROJECT_HOST_$TRAVIS_BRANCH
|
||||
- PROJECT_HOST=${!PROJECT_HOST_VAR}
|
||||
- PROJECT_HOST=${PROJECT_HOST:-$PROJECT_HOST_STAGING}
|
||||
- TEST_PROJECT_ID_master=414835599
|
||||
- TEST_PROJECT_ID_STAGING=1300006196
|
||||
- TEST_PROJECT_ID_VAR=TEST_PROJECT_ID_$TRAVIS_BRANCH
|
||||
- TEST_PROJECT_ID=${!TEST_PROJECT_ID_VAR}
|
||||
- TEST_PROJECT_ID=${TEST_PROJECT_ID:-$TEST_PROJECT_ID_STAGING}
|
||||
- STATIC_HOST_master=https://cdn2.scratch.mit.edu
|
||||
- STATIC_HOST_STAGING=https://cdn.scratch.ly
|
||||
- STATIC_HOST_VAR=STATIC_HOST_$TRAVIS_BRANCH
|
||||
|
|
|
@ -215,11 +215,13 @@ so for the time being our tests run using both.
|
|||
To run all integration tests from the command-line:
|
||||
|
||||
```bash
|
||||
SMOKE_USERNAME=username SMOKE_PASSWORD=password ROOT_URL=https://scratch.mit.edu npm run test:integration
|
||||
SMOKE_USERNAME=username SMOKE_PASSWORD=password ROOT_URL=https://scratch.mit.edu TEST_PROJECT_ID=1 npm run test:integration
|
||||
```
|
||||
|
||||
Both the TAP and Jest tests use the same username and password. The Jest tests will also use the the username you give with a 1 (soon to be higher numbers as well) appended to the end of it. So if you use the username "test" it will also use the username "test1." Make sure you have created accounts with this pattern and use the same password for all accounts involved.
|
||||
|
||||
The project page tests require a project id included as an environment variable to pass. The project must be shared and must have at least one remix. At this time, the project does not need to be owned by one of the test users, but that is likely to change.
|
||||
|
||||
To run a single file from the command-line using Jest:
|
||||
|
||||
```bash
|
||||
|
|
2721
package-lock.json
generated
2721
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -68,7 +68,7 @@
|
|||
"babel-preset-react": "6.22.0",
|
||||
"bowser": "1.9.4",
|
||||
"cheerio": "1.0.0-rc.2",
|
||||
"chromedriver": "84.0.1",
|
||||
"chromedriver": "86.0.0",
|
||||
"classnames": "2.2.5",
|
||||
"cookie": "0.4.1",
|
||||
"copy-webpack-plugin": "0.2.0",
|
||||
|
@ -128,7 +128,7 @@
|
|||
"redux-mock-store": "^1.2.3",
|
||||
"redux-thunk": "2.0.1",
|
||||
"sass-loader": "6.0.6",
|
||||
"scratch-gui": "0.1.0-prerelease.20201015143201",
|
||||
"scratch-gui": "0.1.0-prerelease.20201021170733",
|
||||
"scratch-l10n": "latest",
|
||||
"selenium-webdriver": "3.6.0",
|
||||
"slick-carousel": "1.6.0",
|
||||
|
|
31
src/components/commenting-status/commenting-status.jsx
Normal file
31
src/components/commenting-status/commenting-status.jsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
const classNames = require('classnames');
|
||||
const PropTypes = require('prop-types');
|
||||
const FlexRow = require('../../components/flex-row/flex-row.jsx');
|
||||
const React = require('react');
|
||||
|
||||
|
||||
require('./commenting-status.scss');
|
||||
|
||||
const CommentingStatus = props => (
|
||||
<div className={classNames('commenting-status', props.className)}>
|
||||
<div className={classNames('commenting-status-inner-content', props.innerClassName)}>
|
||||
<FlexRow className="comment-status-img">
|
||||
<img
|
||||
className="comment-status-icon"
|
||||
src="/svgs/project/comment-status.svg"
|
||||
/>
|
||||
</FlexRow>
|
||||
<FlexRow>
|
||||
{props.children}
|
||||
</FlexRow>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
CommentingStatus.propTypes = {
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string,
|
||||
innerClassName: PropTypes.string
|
||||
};
|
||||
|
||||
module.exports = CommentingStatus;
|
23
src/components/commenting-status/commenting-status.scss
Normal file
23
src/components/commenting-status/commenting-status.scss
Normal file
|
@ -0,0 +1,23 @@
|
|||
@import "../../colors";
|
||||
|
||||
.commenting-status {
|
||||
border: 1px solid $ui-blue-10percent;
|
||||
border-radius: 8px;
|
||||
padding: 1.75rem 3rem 2rem;
|
||||
margin: .5rem 0 2.25rem;
|
||||
background-color: $ui-blue-10percent;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
.bottom-text {
|
||||
font-size: .875rem;
|
||||
}
|
||||
.status-icon-class {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
}
|
115
src/components/modal/mute/modal.jsx
Normal file
115
src/components/modal/mute/modal.jsx
Normal file
|
@ -0,0 +1,115 @@
|
|||
const bindAll = require('lodash.bindall');
|
||||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const Modal = require('../base/modal.jsx');
|
||||
const ModalInnerContent = require('../base/modal-inner-content.jsx');
|
||||
const Button = require('../../forms/button.jsx');
|
||||
const Progression = require('../../progression/progression.jsx');
|
||||
const FlexRow = require('../../flex-row/flex-row.jsx');
|
||||
const MuteStep = require('./mute-step.jsx');
|
||||
const classNames = require('classnames');
|
||||
require('./modal.scss');
|
||||
|
||||
class MuteModal extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'handleNext',
|
||||
'handlePrevious'
|
||||
]);
|
||||
this.state = {
|
||||
step: 0
|
||||
};
|
||||
}
|
||||
handleNext () {
|
||||
this.setState({
|
||||
step: this.state.step + 1
|
||||
});
|
||||
}
|
||||
handlePrevious () {
|
||||
// This shouldn't get called when we're on the first step, but
|
||||
// the Math.max is here as a safeguard so state doesn't go negative.
|
||||
this.setState({
|
||||
step: Math.max(0, this.state.step - 1)
|
||||
});
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<Modal
|
||||
isOpen
|
||||
useStandardSizes
|
||||
className="modal-mute"
|
||||
showCloseButton={false}
|
||||
onRequestClose={this.props.onRequestClose}
|
||||
>
|
||||
<div className="mute-modal-header modal-header" />
|
||||
<ModalInnerContent className="mute-inner-content">
|
||||
<Progression step={this.state.step}>
|
||||
<MuteStep
|
||||
bottomImg="/images/bottom_placeholder.png"
|
||||
bottomImgClass="bottom-img"
|
||||
header="The Scratch comment filter thinks your comment was unconstructive."
|
||||
>
|
||||
<p>
|
||||
If you think something could be better, you can say something you like about the project,
|
||||
and make a suggestion about how to improve it. For example, you could say:
|
||||
</p>
|
||||
</MuteStep>
|
||||
<MuteStep
|
||||
header="For the next X minutes you won't be able to post comments"
|
||||
sideImg="/images/side_placeholder.png"
|
||||
sideImgClass="side-img"
|
||||
>
|
||||
<p>
|
||||
Once X minutes have passed, you will be able to comment again.
|
||||
</p>
|
||||
<p>
|
||||
If you would like more information, you can read the Scratch community guidelines.
|
||||
</p>
|
||||
</MuteStep>
|
||||
</Progression>
|
||||
<FlexRow className={classNames('nav-divider')} />
|
||||
<FlexRow className={classNames('mute-nav')}>
|
||||
{this.state.step > 0 ? (
|
||||
<Button
|
||||
className={classNames(
|
||||
'back-button',
|
||||
)}
|
||||
onClick={this.handlePrevious}
|
||||
>
|
||||
<div className="action-button-text">
|
||||
Back
|
||||
</div>
|
||||
</Button>
|
||||
) : null }
|
||||
{this.state.step >= 1 ? (
|
||||
<Button
|
||||
className={classNames('close-button')}
|
||||
onClick={this.props.onRequestClose}
|
||||
>
|
||||
<div className="action-button-text">
|
||||
Close
|
||||
</div>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
className={classNames('next-button')}
|
||||
onClick={this.handleNext}
|
||||
>
|
||||
<div className="action-button-text">
|
||||
Next
|
||||
</div>
|
||||
</Button>
|
||||
)}
|
||||
</FlexRow>
|
||||
</ModalInnerContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MuteModal.propTypes = {
|
||||
onRequestClose: PropTypes.func
|
||||
};
|
||||
|
||||
module.exports = MuteModal;
|
60
src/components/modal/mute/modal.scss
Normal file
60
src/components/modal/mute/modal.scss
Normal file
|
@ -0,0 +1,60 @@
|
|||
@import "../../../colors";
|
||||
@import "../../../frameless";
|
||||
|
||||
.modal-mute {
|
||||
width: 30rem;
|
||||
|
||||
.mute-modal-header {
|
||||
box-shadow: inset 0 -1px 0 0 $ui-mint-green;
|
||||
background-color: $ui-mint-green;
|
||||
border-radius: 1rem 1rem 0 0;
|
||||
}
|
||||
.mute-step {
|
||||
display: flex;
|
||||
padding: 48px 16px;
|
||||
}
|
||||
.mute-content {
|
||||
padding-top: 16px;
|
||||
}
|
||||
.mute-inner-content {
|
||||
padding: 0 32px;
|
||||
}
|
||||
.left-column {
|
||||
padding-right: 32px;
|
||||
}
|
||||
.mute-header {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
line-height: 2rem;
|
||||
}
|
||||
.mute-bottom-row {
|
||||
padding-top: 32px;
|
||||
}
|
||||
.bottom-img {
|
||||
width: 100%;
|
||||
}
|
||||
.mute-side-image {
|
||||
margin-left: -49px;
|
||||
}
|
||||
.side-img {
|
||||
height: 212px;
|
||||
width: 129px;
|
||||
}
|
||||
.nav-divider {
|
||||
border-top: 1px solid $ui-blue-25percent;
|
||||
}
|
||||
.mute-nav {
|
||||
display:flex;
|
||||
justify-content: space-between;
|
||||
padding: 24px 0;
|
||||
}
|
||||
.back-button {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.next-button, .close-button {
|
||||
margin-left: auto;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
55
src/components/modal/mute/mute-step.jsx
Normal file
55
src/components/modal/mute/mute-step.jsx
Normal file
|
@ -0,0 +1,55 @@
|
|||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const classNames = require('classnames');
|
||||
|
||||
const FlexRow = require('../../flex-row/flex-row.jsx');
|
||||
require('./modal.scss');
|
||||
|
||||
const MuteStep = ({
|
||||
bottomImg,
|
||||
bottomImgClass,
|
||||
children,
|
||||
header,
|
||||
sideImg,
|
||||
sideImgClass
|
||||
}) => (
|
||||
<div className="mute-step">
|
||||
{sideImg &&
|
||||
<FlexRow className={classNames('left-column')}>
|
||||
<div className={classNames('mute-side-image')}>
|
||||
<img
|
||||
className={sideImgClass}
|
||||
src={sideImg}
|
||||
/>
|
||||
</div>
|
||||
</FlexRow>
|
||||
}
|
||||
<FlexRow className={classNames('mute-right-column')}>
|
||||
<FlexRow className={classNames('mute-header')}>
|
||||
{header}
|
||||
</FlexRow>
|
||||
<FlexRow className={classNames('mute-content')}>
|
||||
{children}
|
||||
</FlexRow>
|
||||
<FlexRow className={classNames('mute-bottom-row')}>
|
||||
{bottomImg &&
|
||||
<img
|
||||
className={bottomImgClass}
|
||||
src={bottomImg}
|
||||
/>
|
||||
}
|
||||
</FlexRow>
|
||||
</FlexRow>
|
||||
</div>
|
||||
);
|
||||
|
||||
MuteStep.propTypes = {
|
||||
bottomImg: PropTypes.string,
|
||||
bottomImgClass: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
header: PropTypes.string,
|
||||
sideImg: PropTypes.string,
|
||||
sideImgClass: PropTypes.string
|
||||
};
|
||||
|
||||
module.exports = MuteStep;
|
46
src/components/people-grid/people-grid.jsx
Normal file
46
src/components/people-grid/people-grid.jsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const Avatar = require('../../components/avatar/avatar.jsx');
|
||||
|
||||
require('./people-grid.scss');
|
||||
|
||||
const PeopleGrid = props => (
|
||||
<ul className="avatar-grid">
|
||||
{props.people.map((person, index) => (
|
||||
<li
|
||||
className="avatar-item"
|
||||
key={`person-${index}`}
|
||||
>
|
||||
<div>
|
||||
{person.userName ? (
|
||||
<a href={`https://scratch.mit.edu/users/${person.userName}/`}>
|
||||
<Avatar
|
||||
alt=""
|
||||
src={`https://cdn.scratch.mit.edu/get_image/user/${person.userId || 'default'}_80x80.png`}
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
/* if userName is not given, there's no chance userId is given */
|
||||
<Avatar
|
||||
alt=""
|
||||
src={`https://cdn.scratch.mit.edu/get_image/user/default_80x80.png`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<span className="avatar-text">
|
||||
{person.name}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
|
||||
PeopleGrid.propTypes = {
|
||||
people: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
userId: PropTypes.number,
|
||||
userName: PropTypes.string
|
||||
}))
|
||||
};
|
||||
|
||||
module.exports = PeopleGrid;
|
36
src/components/people-grid/people-grid.scss
Normal file
36
src/components/people-grid/people-grid.scss
Normal file
|
@ -0,0 +1,36 @@
|
|||
@import "../../colors";
|
||||
@import "../../frameless";
|
||||
|
||||
.avatar-grid {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
max-width: 864px;
|
||||
list-style: none;
|
||||
flex-wrap: wrap;
|
||||
flex-flow: row wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-item {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding-bottom: 32px;
|
||||
text-align: center;
|
||||
line-height: 1.25rem;
|
||||
|
||||
img {
|
||||
$img-border: rgba(0, 0, 0, .05);
|
||||
border: 2px solid $img-border;
|
||||
border-radius: 8px;
|
||||
background-color: $ui-white;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
display: inline-block;
|
||||
width: 144px;
|
||||
font-size: .875rem;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
|
@ -180,7 +180,7 @@ class UsernameStep extends React.Component {
|
|||
this.props.description
|
||||
) : (
|
||||
<span>
|
||||
<intl.FormattedMessage id="registration.usernameStepDescription" />
|
||||
<intl.FormattedMessage id="registration.usernameStepDescription" />
|
||||
<b>
|
||||
<intl.FormattedMessage id="registration.usernameStepRealName" />
|
||||
</b>
|
||||
|
|
|
@ -2,9 +2,9 @@ const React = require('react');
|
|||
const render = require('../../lib/render.jsx');
|
||||
const FormattedMessage = require('react-intl').FormattedMessage;
|
||||
const injectIntl = require('react-intl').injectIntl;
|
||||
const Avatar = require('../../components/avatar/avatar.jsx');
|
||||
const Page = require('../../components/page/www/page.jsx');
|
||||
const People = require('./people.json');
|
||||
const PeopleGrid = require('../../components/people-grid/people-grid.jsx');
|
||||
const Supporters = require('./supporters.json');
|
||||
const TitleBanner = require('../../components/title-banner/title-banner.jsx');
|
||||
|
||||
|
@ -25,34 +25,7 @@ const Credits = () => (
|
|||
<FormattedMessage id="credits.developers" />
|
||||
</p>
|
||||
</div>
|
||||
<ul className="avatar-grid">
|
||||
{People.map((person, index) => (
|
||||
<li
|
||||
className="avatar-item"
|
||||
key={`person-${index}`}
|
||||
>
|
||||
<div>
|
||||
{person.userName ? (
|
||||
<a href={`https://scratch.mit.edu/users/${person.userName}/`}>
|
||||
<Avatar
|
||||
alt=""
|
||||
src={`https://cdn.scratch.mit.edu/get_image/user/${person.userId || 'default'}_80x80.png`}
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
/* if userName is not given, there's no chance userId is given */
|
||||
<Avatar
|
||||
alt=""
|
||||
src={`https://cdn.scratch.mit.edu/get_image/user/default_80x80.png`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<span className="avatar-text">
|
||||
{person.name}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<PeopleGrid people={People} />
|
||||
</div>
|
||||
<div
|
||||
className="supporters"
|
||||
|
|
|
@ -6,44 +6,12 @@
|
|||
}
|
||||
|
||||
.credits {
|
||||
.avatar-grid {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
padding: 64px 0;
|
||||
max-width: 864px;
|
||||
list-style: none;
|
||||
flex-wrap: wrap;
|
||||
flex-flow: row wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.avatar-item {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding-bottom: 32px;
|
||||
text-align: center;
|
||||
line-height: 1.25rem;
|
||||
|
||||
img {
|
||||
$img-border: rgba(0, 0, 0, .05);
|
||||
border: 2px solid $img-border;
|
||||
border-radius: 8px;
|
||||
background-color: $ui-white;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
display: inline-block;
|
||||
width: 144px;
|
||||
font-size: .875rem;
|
||||
word-wrap: break-word;
|
||||
|
||||
}
|
||||
.avatar-grid {
|
||||
padding: 64px 0;
|
||||
}
|
||||
|
||||
.acknowledge-content {
|
||||
|
|
|
@ -110,6 +110,7 @@ $base-bg: $ui-white;
|
|||
padding-top: 16px;
|
||||
padding-bottom: 32px;
|
||||
width: 100%;
|
||||
overflow-anchor: none;
|
||||
|
||||
.button {
|
||||
display: block;
|
||||
|
|
|
@ -173,7 +173,7 @@
|
|||
"faq.chatRoomBody":"While it is technically possible to create chat rooms with cloud variables, they are not allowed on the Scratch website.",
|
||||
"faq.changeCloudVarTitle":"Who can change the information in a cloud variable?",
|
||||
"faq.changeCloudVarBody":"Only you and viewers of your project can store data in your project’s cloud variables. If people \"see inside\" or remix your code, it creates a copy of the variable and does not affect or change the original variable.",
|
||||
"faq.newScratcherCloudTitle":"I am logged in, but I cannot use projects with cloud variables What is going on?",
|
||||
"faq.newScratcherCloudTitle":"I am logged in, but I cannot use projects with cloud variables. What is going on?",
|
||||
"faq.newScratcherCloudBody":"If you are still a \"New Scratcher\" on the website, you will not be able to use projects with cloud variables. You need to become a \"Scratcher\" to have access to cloud variables. See the Accounts section (above) for more information about the transition from “New Scratcher” to \"Scratcher\".",
|
||||
"faq.multiplayerTitle":"Is it possible to make multiplayer games with cloud variables?",
|
||||
"faq.multiplayerBody":"Multiplayer games may be difficult to create, due to network speed and synchronization issues. However, some Scratchers are coming up with creative ways to use the cloud variables for turn-by-turn and other types of games.",
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.messages-social {
|
||||
overflow-anchor: none;
|
||||
}
|
||||
|
||||
.messages-admin-list,
|
||||
.messages-social-list {
|
||||
padding: 0;
|
||||
|
|
|
@ -230,6 +230,7 @@ $stage-width: 480px;
|
|||
min-width: 65%;
|
||||
max-width: 100%;
|
||||
flex: 1;
|
||||
overflow-anchor: none;
|
||||
|
||||
@media #{$medium-and-smaller} {
|
||||
padding: 0;
|
||||
|
|
|
@ -68,7 +68,7 @@ const OnePointFour = () => (
|
|||
<p><FormattedMessage id="onePointFour.macBody" /></p>
|
||||
<ul className="installation-downloads">
|
||||
<li className="installation-downloads-item">
|
||||
<a href="http://download.scratch.mit.edu/MacScratch1.4.dmg">
|
||||
<a href="https://download.scratch.mit.edu/MacScratch1.4.dmg">
|
||||
MacScratch1.4.dmg
|
||||
</a>
|
||||
</li>
|
||||
|
@ -86,7 +86,7 @@ const OnePointFour = () => (
|
|||
key="installation-downloads"
|
||||
>
|
||||
<li className="installation-downloads-item">
|
||||
<a href="http://download.scratch.mit.edu/ScratchInstaller1.4.exe">
|
||||
<a href="https://download.scratch.mit.edu/ScratchInstaller1.4.exe">
|
||||
ScratchInstaller1.4.exe
|
||||
</a>
|
||||
</li>
|
||||
|
@ -95,7 +95,7 @@ const OnePointFour = () => (
|
|||
id="onePointFour.windowsNetwork"
|
||||
values={{
|
||||
windowsNetworkInstaller: (
|
||||
<a href="http://download.scratch.mit.edu/Scratch1.4.msi.installer.zip">
|
||||
<a href="https://download.scratch.mit.edu/Scratch1.4.msi.installer.zip">
|
||||
<FormattedMessage id="onePointFour.windowsNetworkInstaller" />
|
||||
</a>
|
||||
)
|
||||
|
@ -144,17 +144,17 @@ const OnePointFour = () => (
|
|||
id="onePointFour.resourcesA"
|
||||
values={{
|
||||
gettingStartedGuide: (
|
||||
<a href="http://download.scratch.mit.edu/ScratchGettingStartedv14.pdf">
|
||||
<a href="https://download.scratch.mit.edu/ScratchGettingStartedv14.pdf">
|
||||
<FormattedMessage id="onePointFour.gettingStartedGuide" />
|
||||
</a>
|
||||
),
|
||||
referenceGuide: (
|
||||
<a href="http://download.scratch.mit.edu/ScratchReferenceGuide14.pdf">
|
||||
<a href="https://download.scratch.mit.edu/ScratchReferenceGuide14.pdf">
|
||||
<FormattedMessage id="onePointFour.referenceGuide" />
|
||||
</a>
|
||||
),
|
||||
scratchCards: (
|
||||
<a href="http://download.scratch.mit.edu/ScratchCardsAll-v1.4-PDF.zip">
|
||||
<a href="https://download.scratch.mit.edu/ScratchCardsAll-v1.4-PDF.zip">
|
||||
<FormattedMessage id="onePointFour.scratchCards" />
|
||||
</a>
|
||||
)
|
||||
|
|
1
static/svgs/project/comment-status.svg
Normal file
1
static/svgs/project/comment-status.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M9 16c-1 1-3.5 2.5-4 2s0-1 0-2H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9zm-3-6a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H6zm0-4a1 1 0 1 0 0 2h8a1 1 0 0 0 0-2H6z" id="a"/></defs><g fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><use fill="#575E75" xlink:href="#a"/><g mask="url(#b)" fill="#4D97FF"><path d="M0 0h20v20H0z"/></g></g></svg>
|
After Width: | Height: | Size: 510 B |
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
* Checks that the links in the footer on the homepage have the right URLs to redirect to
|
||||
*
|
||||
* Test cases: https://github.com/LLK/scratch-www/wiki/Most-Important-Workflows
|
||||
*/
|
||||
|
||||
const SeleniumHelper = require('../selenium-helpers.js');
|
||||
const helper = new SeleniumHelper();
|
||||
|
||||
const tap = require('tap');
|
||||
|
||||
const webdriver = require('selenium-webdriver');
|
||||
const driver = helper.buildDriver('www-smoke test_footer_links');
|
||||
|
||||
const rootUrl = process.env.ROOT_URL || 'https://scratch.ly';
|
||||
|
||||
// timeout for each test; timeout for suite set at command line level
|
||||
const options = {timeout: 30000};
|
||||
|
||||
tap.tearDown(function () {
|
||||
// quit the instance of the browser
|
||||
driver.quit();
|
||||
});
|
||||
|
||||
tap.beforeEach(function () {
|
||||
// load the page with the driver
|
||||
return driver.get(rootUrl);
|
||||
});
|
||||
|
||||
// Function clicks the link and returns the url of the resulting page
|
||||
|
||||
const clickFooterLinks = function (linkText) {
|
||||
return driver.wait(webdriver.until.elementLocated(webdriver.By.id('footer')))
|
||||
.then(function (element) {
|
||||
return element.findElement(webdriver.By.linkText(linkText));
|
||||
})
|
||||
.then(function (element) {
|
||||
return element.click();
|
||||
})
|
||||
.then(function () {
|
||||
return driver.getCurrentUrl();
|
||||
});
|
||||
};
|
||||
|
||||
// ==== ABOUT SCRATCH column ====
|
||||
|
||||
// ABOUT SCRATCH
|
||||
tap.test('clickAboutScratchLink', options, t => {
|
||||
const linkText = 'About Scratch';
|
||||
const expectedHref = '/about';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
// the href should be at the end of the URL
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// FOR PARENTS
|
||||
tap.test('clickForParentsLink', options, t => {
|
||||
const linkText = 'For Parents';
|
||||
const expectedHref = '/parents/';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// FOR EDUCATORS
|
||||
tap.test('clickForEducatorsLink', options, t => {
|
||||
const linkText = 'For Educators';
|
||||
const expectedHref = '/educators';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// FOR DEVELOPERS
|
||||
tap.test('clickForDevelopersScratchLink', options, t => {
|
||||
const linkText = 'For Developers';
|
||||
const expectedHref = '/developers';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// CREDITS
|
||||
tap.test('clickCreditsLink', options, t => {
|
||||
const linkText = 'Credits';
|
||||
const expectedHref = '/credits';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// JOBS
|
||||
tap.test('clickJobsLink', options, t => {
|
||||
const linkText = 'Jobs';
|
||||
const expectedUrl = 'https://www.scratchfoundation.org/opportunities/';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url, expectedUrl);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// PRESS
|
||||
tap.test('clickPressLink', options, t => {
|
||||
const linkText = 'Press';
|
||||
const expectedUrl = 'https://www.scratchfoundation.org/media-kit/';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url, expectedUrl);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// ==== COMMUNITY column ====
|
||||
|
||||
// COMMUNITY GUIDELINES
|
||||
tap.test('clickCommunityGuidelinesLink', options, t => {
|
||||
const linkText = 'Community Guidelines';
|
||||
const expectedHref = '/community_guidelines';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// DISCUSSION FORUMS
|
||||
tap.test('clickDiscussionForumsLink', options, t => {
|
||||
const linkText = 'Discussion Forums';
|
||||
const expectedHref = '/discuss/';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// STATISTICS
|
||||
tap.test('clickStatisticsLink', options, t => {
|
||||
const linkText = 'Statistics';
|
||||
const expectedHref = '/statistics/';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// ==== SUPPORT column ====
|
||||
|
||||
// IDEAS PAGE
|
||||
tap.test('clickIdeasPageLink', options, t => {
|
||||
const linkText = 'Ideas';
|
||||
const expectedHref = '/ideas';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// FAQ
|
||||
tap.test('clickFAQLink', options, t => {
|
||||
const linkText = 'FAQ';
|
||||
const expectedHref = '/info/faq';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// OFFLINE EDITOR
|
||||
tap.test('clickOfflineEditorLink', options, t => {
|
||||
const linkText = 'Offline Editor';
|
||||
const expectedHref = '/download';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// CONTACT US
|
||||
tap.test('clickContactUsLink', options, t => {
|
||||
const linkText = 'Contact Us';
|
||||
const expectedHref = '/contact-us/';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// ==== LEGAL column ====
|
||||
|
||||
// TERMS OF USE
|
||||
tap.test('clickTermsOfUseLink', options, t => {
|
||||
const linkText = 'Terms of Use';
|
||||
const expectedHref = '/terms_of_use';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// PRIVACY POLICY
|
||||
tap.test('clickPrivacyPolicyLink', options, t => {
|
||||
const linkText = 'Privacy Policy';
|
||||
const expectedHref = '/privacy_policy';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// DMCA
|
||||
tap.test('clickDMCALink', options, t => {
|
||||
const linkText = 'DMCA';
|
||||
const expectedHref = '/DMCA';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.equal(url.substr(-expectedHref.length), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
// ==== SCRATCH FAMILY column ====
|
||||
// SCRATCH CONFERENCE
|
||||
tap.test('clickScratchConferenceLink', options, t => {
|
||||
const linkText = 'Scratch Conference';
|
||||
const expectedHref = '/conference/20';
|
||||
clickFooterLinks(linkText).then(url => {
|
||||
t.match(url.substr(-(expectedHref.length + 2)), expectedHref);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
// The following links in are skipped because they are not on scratch.mit.edu
|
||||
|
||||
// SCRATCH STORE
|
||||
// DONATE
|
||||
// SCRATCH WIKI
|
||||
// SCRATCH ED (SCRATCHED)
|
||||
// SCRATCH JR (SCRATCHJR)
|
||||
// SCRATCH DAY
|
||||
// SCRATCH FOUNDATION
|
|
@ -1,61 +0,0 @@
|
|||
const SeleniumHelper = require('../selenium-helpers.js');
|
||||
const helper = new SeleniumHelper();
|
||||
|
||||
var tap = require('tap');
|
||||
const test = tap.test;
|
||||
|
||||
const driver = helper.buildDriver('www-smoke test_sign_in_out_homepage');
|
||||
|
||||
const {
|
||||
clickText,
|
||||
clickXpath,
|
||||
dragFromXpathToXpath,
|
||||
findByXpath,
|
||||
waitUntilGone
|
||||
} = helper;
|
||||
|
||||
const rootUrl = process.env.ROOT_URL || 'https://scratch.ly';
|
||||
const projectId = 1;
|
||||
const projectUrl = `${rootUrl}/projects/${projectId}`;
|
||||
|
||||
tap.plan(3);
|
||||
|
||||
tap.tearDown(function () {
|
||||
driver.quit();
|
||||
});
|
||||
|
||||
tap.beforeEach(function () {
|
||||
return driver.get(projectUrl);
|
||||
});
|
||||
|
||||
test('Find fullscreen button', {skip: true}, t => {
|
||||
findByXpath('//div[starts-with(@class, "loader_background")]')
|
||||
.then(el => waitUntilGone(el))
|
||||
.then(() => clickXpath('//div[starts-with(@class, "stage_green-flag-overlay")]'))
|
||||
.then(() => clickXpath('//img[contains(@alt, "Enter full screen mode")]'))
|
||||
.then(() => t.end());
|
||||
});
|
||||
|
||||
test('Open and close Copy Link modal', {skip: true}, t => {
|
||||
findByXpath('//div[starts-with(@class, "loader_background")]')
|
||||
.then(el => waitUntilGone(el))
|
||||
.then(() => clickText('Copy Link'))
|
||||
.then(() => clickXpath('//div[contains(@class, "social-label-title")]'))
|
||||
.then(() => clickXpath('//img[contains(@alt, "close-icon")]'))
|
||||
.then(() => clickXpath('//img[contains(@alt, "Enter full screen mode")]'))
|
||||
.then(() => t.end());
|
||||
});
|
||||
|
||||
test('Dragging out of modal should not close modal', {skip: true}, t => {
|
||||
findByXpath('//div[starts-with(@class, "loader_background")]')
|
||||
.then(el => waitUntilGone(el))
|
||||
.then(() => clickXpath('//div[starts-with(@class, "stage_green-flag-overlay")]'))
|
||||
.then(() => clickText('Copy Link'))
|
||||
.then(() => clickXpath('//div[contains(@class, "social-label-title")]'))
|
||||
.then(() => dragFromXpathToXpath(
|
||||
'//div[contains(@class, "social-label-title")]',
|
||||
'//li[contains(@class, "logo")]'
|
||||
))
|
||||
.then(() => clickXpath('//div[contains(@class, "social-label-title")]'))
|
||||
.then(() => t.end());
|
||||
});
|
157
test/integration/footer-links.test.js
Normal file
157
test/integration/footer-links.test.js
Normal file
|
@ -0,0 +1,157 @@
|
|||
const SeleniumHelper = require('./selenium-helpers.js');
|
||||
|
||||
const {
|
||||
clickText,
|
||||
buildDriver
|
||||
} = new SeleniumHelper();
|
||||
|
||||
let remote = process.env.SMOKE_REMOTE || false;
|
||||
let rootUrl = process.env.ROOT_URL || 'https://scratch.ly';
|
||||
|
||||
if (remote) {
|
||||
jest.setTimeout(60000);
|
||||
} else {
|
||||
jest.setTimeout(10000);
|
||||
}
|
||||
|
||||
let driver;
|
||||
|
||||
describe('www-integration footer links', () => {
|
||||
beforeAll(async () => {
|
||||
driver = await buildDriver('www-integration footer links');
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await driver.get(rootUrl);
|
||||
});
|
||||
|
||||
afterAll(async () => await driver.quit());
|
||||
|
||||
// ==== About Scratch column ====
|
||||
|
||||
test('click About Scratch link', async () => {
|
||||
await clickText('About Scratch');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/about\/?$/);
|
||||
});
|
||||
|
||||
test('click For Parents link', async () => {
|
||||
await clickText('For Parents');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/parents\/?$/);
|
||||
});
|
||||
|
||||
test('click For Educators link', async () => {
|
||||
await clickText('For Educators');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/educators\/?$/);
|
||||
});
|
||||
|
||||
test('click For Developers link', async () => {
|
||||
await clickText('For Developers');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/developers\/?$/);
|
||||
});
|
||||
|
||||
// ==== COMMUNITY column ====
|
||||
|
||||
test('click Community Guidelines link', async () => {
|
||||
await clickText('Community Guidelines');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/community_guidelines\/?$/);
|
||||
});
|
||||
|
||||
test('click Discussion Forums link', async () => {
|
||||
await clickText('Discussion Forums');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/discuss\/?$/);
|
||||
});
|
||||
|
||||
test('click Statistics link', async () => {
|
||||
await clickText('Statistics');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/statistics\/?$/);
|
||||
});
|
||||
|
||||
// ==== SUPPORT column ====
|
||||
|
||||
test('click Ideas link', async () => {
|
||||
await clickText('Ideas');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/ideas\/?$/);
|
||||
});
|
||||
|
||||
test('click FAQ link', async () => {
|
||||
await clickText('FAQ');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/info\/faq\/?$/);
|
||||
});
|
||||
|
||||
test('click Download link', async () => {
|
||||
await clickText('Download');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/download\/?$/);
|
||||
});
|
||||
|
||||
test('click Contact Us link', async () => {
|
||||
await clickText('Contact Us');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/contact-us\/?$/);
|
||||
});
|
||||
|
||||
// ==== LEGAL column ====
|
||||
|
||||
test('click Terms of Use link', async () => {
|
||||
await clickText('Terms of Use');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/terms_of_use\/?$/);
|
||||
});
|
||||
|
||||
test('click Privacy Policy link', async () => {
|
||||
await clickText('Privacy Policy');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/privacy_policy\/?$/);
|
||||
});
|
||||
|
||||
test('click DMCA link', async () => {
|
||||
await clickText('DMCA');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/DMCA\/?$/);
|
||||
});
|
||||
|
||||
// ==== SCRATCH FAMILY column ====
|
||||
|
||||
test('click Scratch Conference link', async () => {
|
||||
await clickText('Scratch Conference');
|
||||
let url = await driver.getCurrentUrl();
|
||||
let pathname = (new URL(url)).pathname;
|
||||
expect(pathname).toMatch(/^\/conference\/2020\/?$/);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// The following links in are skipped because they are not on scratch.mit.edu
|
||||
|
||||
// Jobs
|
||||
// Press
|
||||
// SCRATCH STORE
|
||||
// DONATE
|
||||
// SCRATCH WIKI
|
||||
// SCRATCH ED (SCRATCHED)
|
||||
// SCRATCH JR (SCRATCHJR)
|
||||
// SCRATCH DAY
|
||||
// SCRATCH FOUNDATION
|
74
test/integration/project-page.test.js
Normal file
74
test/integration/project-page.test.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
const SeleniumHelper = require('./selenium-helpers.js');
|
||||
|
||||
const {
|
||||
findByXpath,
|
||||
clickXpath,
|
||||
buildDriver
|
||||
} = new SeleniumHelper();
|
||||
|
||||
let remote = process.env.SMOKE_REMOTE || false;
|
||||
let rootUrl = process.env.ROOT_URL || 'https://scratch.ly';
|
||||
let projectId = process.env.TEST_PROJECT_ID || 1300006196;
|
||||
let projectUrl = rootUrl + '/projects/' + projectId;
|
||||
|
||||
if (remote){
|
||||
jest.setTimeout(60000);
|
||||
} else {
|
||||
jest.setTimeout(10000);
|
||||
}
|
||||
|
||||
let driver;
|
||||
|
||||
describe('www-integration project-page signed out', () => {
|
||||
beforeAll(async () => {
|
||||
// expect(projectUrl).toBe(defined);
|
||||
driver = await buildDriver('www-integration project-page signed out');
|
||||
await driver.get(rootUrl);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await driver.get(projectUrl);
|
||||
let gfOverlay = await findByXpath('//div[@class="stage-wrapper_stage-wrapper_2bejr box_box_2jjDp"]');
|
||||
await gfOverlay.isDisplayed();
|
||||
});
|
||||
|
||||
afterAll(async () => await driver.quit());
|
||||
|
||||
// LOGGED OUT TESTS
|
||||
|
||||
test('Find fullscreen button', async () => {
|
||||
await clickXpath('//div[starts-with(@class, "stage_green-flag-overlay")]');
|
||||
await clickXpath('//img[contains(@alt, "Enter full screen mode")]');
|
||||
let fullscreenGui = await findByXpath('//div[@class="guiPlayer fullscreen"]');
|
||||
let guiVisible = await fullscreenGui.isDisplayed();
|
||||
await expect(guiVisible).toBe(true);
|
||||
});
|
||||
|
||||
test.skip('Open Copy Link modal', async () => {
|
||||
await clickXpath('//button[@class="button action-button copy-link-button"]');
|
||||
let projectLink = await findByXpath('//input[@name="link"]');
|
||||
let linkValue = await projectLink.getAttribute('value');
|
||||
await expect(linkValue).toEqual(projectUrl);
|
||||
});
|
||||
|
||||
test('Click Username to go to profile page', async ()=> {
|
||||
await clickXpath('//div[@class="title"]/a');
|
||||
let userContent = await findByXpath('//div[@class="user-content"]');
|
||||
let contentVisible = await userContent.isDisplayed();
|
||||
await expect(contentVisible).toBe(true);
|
||||
});
|
||||
|
||||
test('click See Inside to go to the editor', async ()=> {
|
||||
await clickXpath('//button[@class="button button see-inside-button"]');
|
||||
let infoArea = await findByXpath('//div[@class="sprite-info_sprite-info_3EyZh box_box_2jjDp"]');
|
||||
let areaVisible = await infoArea.isDisplayed();
|
||||
await expect(areaVisible).toBe(true);
|
||||
});
|
||||
|
||||
test('click View All remixes takes you to remix page', async ()=> {
|
||||
await clickXpath('//div[@class="list-header-link"]');
|
||||
let originalLink = await findByXpath('//h2/a');
|
||||
let link = await originalLink.getAttribute('href');
|
||||
await expect(link).toEqual(rootUrl + '/projects/' + projectId + '/');
|
||||
});
|
||||
});
|
33
test/unit/components/commenting-status.test.jsx
Normal file
33
test/unit/components/commenting-status.test.jsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
const React = require('react');
|
||||
const {shallowWithIntl} = require('../../helpers/intl-helpers.jsx');
|
||||
const CommentingStatus = require('../../../src/components/commenting-status/commenting-status.jsx');
|
||||
|
||||
describe('CommentingStatus', () => {
|
||||
test('Basic render', () => {
|
||||
const component = shallowWithIntl(
|
||||
<CommentingStatus />
|
||||
);
|
||||
expect(component.find('div.commenting-status').exists()).toBe(true);
|
||||
expect(component.find('img.comment-status-icon').exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('ClassNames added', () => {
|
||||
const component = shallowWithIntl(
|
||||
<CommentingStatus
|
||||
className="class1"
|
||||
innerClassName="class2"
|
||||
/>
|
||||
);
|
||||
expect(component.find('div.class1').exists()).toBe(true);
|
||||
expect(component.find('div.class2').exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('Children added', () => {
|
||||
const component = shallowWithIntl(
|
||||
<CommentingStatus>
|
||||
<img className="myChildDiv" />
|
||||
</CommentingStatus>
|
||||
);
|
||||
expect(component.find('img.myChildDiv').exists()).toBe(true);
|
||||
});
|
||||
});
|
93
test/unit/components/mute-modal.test.jsx
Normal file
93
test/unit/components/mute-modal.test.jsx
Normal file
|
@ -0,0 +1,93 @@
|
|||
import React from 'react';
|
||||
import {shallowWithIntl} from '../../helpers/intl-helpers.jsx';
|
||||
import {mountWithIntl} from '../../helpers/intl-helpers.jsx';
|
||||
import MuteModal from '../../../src/components/modal/mute/modal';
|
||||
import Modal from '../../../src/components/modal/base/modal';
|
||||
|
||||
|
||||
describe('MuteModalTest', () => {
|
||||
|
||||
test('Mute Modal rendering', () => {
|
||||
const component = shallowWithIntl(
|
||||
<MuteModal />
|
||||
);
|
||||
expect(component.find('div.mute-modal-header').exists()).toEqual(true);
|
||||
|
||||
});
|
||||
|
||||
test('Mute Modal only shows next button on initial step', () => {
|
||||
const component = mountWithIntl(
|
||||
<MuteModal />
|
||||
);
|
||||
expect(component.find('div.mute-nav').exists()).toEqual(true);
|
||||
expect(component.find('button.next-button').exists()).toEqual(true);
|
||||
expect(component.find('button.next-button').getElements()[0].props.onClick)
|
||||
.toEqual(component.instance().handleNext);
|
||||
expect(component.find('button.close-button').exists()).toEqual(false);
|
||||
expect(component.find('button.back-button').exists()).toEqual(false);
|
||||
});
|
||||
|
||||
test('Mute Modal shows back & close button on last step', () => {
|
||||
const component = mountWithIntl(
|
||||
<MuteModal />
|
||||
);
|
||||
// Step 1 is the last step.
|
||||
component.instance().setState({step: 1});
|
||||
component.update();
|
||||
|
||||
expect(component.find('div.mute-nav').exists()).toEqual(true);
|
||||
expect(component.find('button.next-button').exists()).toEqual(false);
|
||||
expect(component.find('button.back-button').exists()).toEqual(true);
|
||||
expect(component.find('button.back-button').getElements()[0].props.onClick)
|
||||
.toEqual(component.instance().handlePrevious);
|
||||
expect(component.find('button.close-button').exists()).toEqual(true);
|
||||
expect(component.find('button.close-button').getElements()[0].props.onClick)
|
||||
.toEqual(component.instance().props.onRequestClose);
|
||||
});
|
||||
|
||||
test('Mute modal sends correct props to Modal', () => {
|
||||
const closeFn = jest.fn();
|
||||
const component = shallowWithIntl(
|
||||
<MuteModal
|
||||
onRequestClose={closeFn}
|
||||
/>
|
||||
);
|
||||
const modal = component.find(Modal);
|
||||
expect(modal).toHaveLength(1);
|
||||
expect(modal.props().showCloseButton).toBe(false);
|
||||
expect(modal.props().isOpen).toBe(true);
|
||||
expect(modal.props().className).toBe('modal-mute');
|
||||
expect(modal.props().onRequestClose).toBe(closeFn);
|
||||
});
|
||||
|
||||
test('Mute modal handle next step', () => {
|
||||
const closeFn = jest.fn();
|
||||
const component = shallowWithIntl(
|
||||
<MuteModal
|
||||
onRequestClose={closeFn}
|
||||
/>
|
||||
);
|
||||
expect(component.instance().state.step).toBe(0);
|
||||
component.instance().handleNext();
|
||||
expect(component.instance().state.step).toBe(1);
|
||||
});
|
||||
|
||||
test('Mute modal handle previous step', () => {
|
||||
const component = shallowWithIntl(
|
||||
<MuteModal />
|
||||
);
|
||||
component.instance().setState({step: 1});
|
||||
|
||||
component.instance().handlePrevious();
|
||||
expect(component.instance().state.step).toBe(0);
|
||||
});
|
||||
|
||||
test('Mute modal handle previous step stops at 0', () => {
|
||||
const component = shallowWithIntl(
|
||||
<MuteModal />
|
||||
);
|
||||
component.instance().setState({step: 0});
|
||||
component.instance().handlePrevious();
|
||||
expect(component.instance().state.step).toBe(0);
|
||||
});
|
||||
});
|
49
test/unit/components/mute-step.test.jsx
Normal file
49
test/unit/components/mute-step.test.jsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import React from 'react';
|
||||
import {mountWithIntl} from '../../helpers/intl-helpers.jsx';
|
||||
import MuteStep from '../../../src/components/modal/mute/mute-step';
|
||||
|
||||
describe('MuteStepTest', () => {
|
||||
test('Mute Step with no images ', () => {
|
||||
const component = mountWithIntl(
|
||||
<MuteStep
|
||||
header="header text"
|
||||
|
||||
/>
|
||||
);
|
||||
expect(component.find('div.mute-step').exists()).toEqual(true);
|
||||
expect(component.find('div.mute-header').exists()).toEqual(true);
|
||||
expect(component.find('div.mute-right-column').exists()).toEqual(true);
|
||||
// No images and no left column.
|
||||
expect(component.find('img').exists()).toEqual(false);
|
||||
expect(component.find('div.left-column').exists()).toEqual(false);
|
||||
|
||||
});
|
||||
|
||||
test('Mute Step with side image ', () => {
|
||||
const component = mountWithIntl(
|
||||
<MuteStep
|
||||
sideImg="/path/to/img.png"
|
||||
sideImgClass="side-img"
|
||||
/>
|
||||
);
|
||||
expect(component.find('div.mute-step').exists()).toEqual(true);
|
||||
expect(component.find('div.mute-header').exists()).toEqual(true);
|
||||
expect(component.find('div.mute-right-column').exists()).toEqual(true);
|
||||
expect(component.find('div.left-column').exists()).toEqual(true);
|
||||
expect(component.find('img.side-img').exists()).toEqual(true);
|
||||
|
||||
});
|
||||
|
||||
test('Mute Step with bottom image ', () => {
|
||||
const component = mountWithIntl(
|
||||
<MuteStep
|
||||
bottomImg="/path/to/img.png"
|
||||
bottomImgClass="bottom-image"
|
||||
/>
|
||||
);
|
||||
expect(component.find('div.mute-step').exists()).toEqual(true);
|
||||
expect(component.find('div.mute-header').exists()).toEqual(true);
|
||||
expect(component.find('div.mute-right-column').exists()).toEqual(true);
|
||||
expect(component.find('img.bottom-image').exists()).toEqual(true);
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue