Skip to content
Commits on Source (682)
...@@ -7,17 +7,14 @@ ...@@ -7,17 +7,14 @@
{ {
"root": "src", "root": "src",
"outDir": "dist", "outDir": "dist",
"assets": [ "assets": ["assets", "favicon.ico"],
"assets",
"favicon.ico"
],
"index": "index.php", "index": "index.php",
"main": "main.ts", "main": "main.ts",
"polyfills": "polyfills.ts", "polyfills": "polyfills.ts",
"test": "test.ts", "test": "test.ts",
"tsconfig": "tsconfig.app.json", "tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json", "testTsconfig": "tsconfig.spec.json",
"prefix": "app", "prefix": "m",
"styles": [ "styles": [
"../node_modules/material-design-lite/dist/material.blue_grey-amber.min.css", "../node_modules/material-design-lite/dist/material.blue_grey-amber.min.css",
"../node_modules/material-design-icons/iconfont/material-icons.css", "../node_modules/material-design-icons/iconfont/material-icons.css",
...@@ -26,7 +23,6 @@ ...@@ -26,7 +23,6 @@
"scripts": [ "scripts": [
"../node_modules/material-design-lite/dist/material.min.js", "../node_modules/material-design-lite/dist/material.min.js",
"../node_modules/medium-editor/dist/js/medium-editor.min.js", "../node_modules/medium-editor/dist/js/medium-editor.min.js",
"shims/fontawesome.js",
"shims/jitsi-api.min.js" "shims/jitsi-api.min.js"
], ],
"environmentSource": "environments/environment.ts", "environmentSource": "environments/environment.ts",
......
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
cat <<\EOF
#Error: Attempt to add a non-ASCII file name.
#
#This can cause problems if you want to work with people on other platforms.
#
#To be portable it is advisable to rename the file.
#
#If you know what you are doing you can disable this check using:
#
# git config hooks.allownonascii true
EOF
exit 1
fi
# If there are whitespace errors, print the offending file names and fail.
#exec git diff-index --check --cached $against --
# Check for "fdescribe"-esque development artifacts accidentally left in.
# https://gist.github.com/DerLobi/d938ac7dc422145f85e6#gistcomment-2824
STATUS=0
for focus in fdescribe fcontext fit fspecify fexample; do
FILES=$(git diff --staged -G"^\s*$focus\(" --name-only | wc -l)
if [ $FILES -gt 0 ]
then
echo "You forgot to remove a $focus in the following files:"
git diff --staged --name-only -G"^\s*$focus\("
echo ""
STATUS=1
fi
done
exit $STATUS
...@@ -31,7 +31,12 @@ tmtags ...@@ -31,7 +31,12 @@ tmtags
Thumbs.db Thumbs.db
Desktop.ini Desktop.ini
node_modules node_modules
cypress/screenshots
cypress/videos
# don't ignore travis config # don't ignore travis config
!/.travis.yml !/.travis.yml
!/.drone.yml !/.drone.yml
!/.gitlab !/.gitlab
!/.githooks
!/.prettierrc
!.gitattributes
image: markharding/minds-front-base image: markharding/minds-front-base
services:
- docker:dind
stages: stages:
- test - test
- build - build
- deploy - prepare
- review
- deploy:staging
- qa
- deploy:canary
- deploy:production
- cleanup
variables:
CYPRESS_INSTALL_BINARY: 0 # Speeds up the install process
npm_config_cache: '$CI_PROJECT_DIR/.npm'
CYPRESS_CACHE_FOLDER: '$CI_PROJECT_DIR/cache/Cypress'
test: test:
image: circleci/node:8-browsers image: circleci/node:8-browsers
stage: test stage: test
script: script:
- npm install # Should be cached... - npm ci
- npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI - npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI
build: lint:
stage: test
script:
- npm i -g prettier
- prettier --check "src/**/*.ts"
- prettier --check "src/**/*.scss"
- prettier --check "src/**/*.html"
############
# QA Stage #
############
qa:e2e:
image: cypress/browsers:chrome67
stage: qa
variables:
CYPRESS_INSTALL_BINARY: 3.4.1
script:
- npm ci
- >
if [ "$CI_BUILD_REF_NAME" == "master" ]; then
export E2E_DOMAIN=https://www.minds.com
export PRODUCTION=true
else
export E2E_DOMAIN=https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
export PRODUCTION=false
fi
- export CYPRESS_baseUrl=$E2E_DOMAIN
- echo "E2E tests for $CI_BUILD_REF_NAME running against $E2E_DOMAIN with user $CYPRESS_username"
- $(npm bin)/cypress run --browser chrome --record --key $CYPRESS_RECORD_ID --config CYPRESS_baseUrl=$E2E_DOMAIN,production=$PRODUCTION
artifacts:
when: always
paths:
- cypress/screenshots
- cypress/videos
cache:
paths:
- .npm
- cache/Cypress
allow_failure: true #manual inspection in case of timeouts
qa:manual:
stage: qa
script:
- echo "Manually approved"
when: manual
only:
refs:
- master
- test/gitlab-ci
allow_failure: false
###############
# Build Stage #
###############
build:review:
stage: build stage: build
before_script:
- sed -ri "s|'VERSION'|'$CI_PIPELINE_ID'|" src/environments/environment.prod.ts
script: script:
- npm install # TODO: Why is this needed? - npm ci && npm install -g gulp-cli
- npm run postinstall
- gulp build.sass && gulp build.sass ##weird build needs to be run twice for now
- sh build/base-locale.sh dist
artifacts:
name: '$CI_COMMIT_REF_SLUG'
paths:
- dist
except:
refs:
- master
- test/gitlab-ci
build:production:en:
stage: build
before_script:
- sed -ri "s|'VERSION'|'$CI_PIPELINE_ID'|" src/environments/environment.prod.ts
script:
- npm ci && npm install -g gulp-cli
- npm run postinstall - npm run postinstall
- npm install -g gulp-cli
- gulp build.sass --deploy-url=https://cdn-assets.minds.com/front/dist/en && gulp build.sass --deploy-url=https://cdn-assets.minds.com/front/dist/en ##weird build needs to be run twice for now - gulp build.sass --deploy-url=https://cdn-assets.minds.com/front/dist/en && gulp build.sass --deploy-url=https://cdn-assets.minds.com/front/dist/en ##weird build needs to be run twice for now
- sh build/base-locale.sh dist https://cdn-assets.minds.com/front/dist - sh build/base-locale.sh dist https://cdn-assets.minds.com/front/dist
- sh build/i18n-locales-all.sh dist https://cdn-assets.minds.com/front/dist artifacts:
cache: name: '$CI_COMMIT_REF_SLUG'
paths: paths:
- dist - dist/en
policy: push
only: only:
refs: refs:
- master - master
- test/gitlab-ci - test/gitlab-ci
deploy: build:production:i18n:
stage: deploy stage: build
before_script:
- sed -ri "s|'VERSION'|'$CI_PIPELINE_ID'|" src/environments/environment.prod.ts
script: script:
- apk add --no-cache python py-pip - npm ci && npm install -g gulp-cli
- pip install awscli - npm run postinstall
- aws s3 sync dist $REPOSITORY_URL - gulp build.sass --deploy-url=https://cdn-assets.minds.com/front/dist/en && gulp build.sass --deploy-url=https://cdn-assets.minds.com/front/dist/en ##weird build needs to be run twice for now
- aws ecs update-service --service=$SERVICE --force-new-deployment --region us-east-1 --cluster=$CLUSTER - sh build/i18n-locales-all.sh dist https://cdn-assets.minds.com/front/dist
cache: artifacts:
name: '$CI_COMMIT_REF_SLUG'
paths: paths:
- dist - dist/vi
policy: pull only:
refs:
- master
- test/gitlab-ci
#################
# Prepare Stage #
#################
.sentry_prepare: &sentry_prepare
stage: prepare
image: getsentry/sentry-cli
script:
- echo "Create a new release $CI_PIPELINE_ID"
- sentry-cli releases new $CI_PIPELINE_ID
- sentry-cli releases set-commits --auto $CI_PIPELINE_ID
- sentry-cli releases files $CI_PIPELINE_ID upload-sourcemaps $CI_PROJECT_DIR/dist/en -x .js -x .map --validate --url-prefix $SOURCEMAP_PREFIX
- sentry-cli releases finalize $CI_PIPELINE_ID
- echo "Finalized release for $CI_PIPELINE_ID"
prepare:review:
stage: prepare
image: minds/ci:latest
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker build -t $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID -f containers/front-init/Dockerfile dist/.
- docker push $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID
dependencies:
- build:review
except:
refs:
- master
- test/gitlab-ci
prepare:review:sentry:
<<: *sentry_prepare
variables:
SOURCEMAP_PREFIX: '~/en'
except:
refs:
- master
- test/gitlab-ci
dependencies:
- build:review
prepare:production:
stage: prepare
image: minds/ci:latest
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker build -t $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID -f containers/front-init/Dockerfile dist/.
- docker push $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID
only: only:
refs: refs:
- master - master
- test/gitlab-ci - test/gitlab-ci
dependencies:
- build:production:en
- build:production:i18n
prepare:production:sentry:
<<: *sentry_prepare
variables:
SOURCEMAP_PREFIX: '~/front/dist/en'
only:
refs:
- master
- test/gitlab-ci
dependencies:
- build:production:en
- build:production:i18n
################
# Review Stage #
################
.cleanup_review: &cleanup_review
image: minds/helm-eks:latest
script:
- aws eks update-kubeconfig --name=sandbox
- helm del --purge $CI_BUILD_REF_SLUG
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
action: stop
variables:
GIT_STRATEGY: none
except:
refs:
- master
- test/gitlab-ci
review:start:
stage: review
image: minds/helm-eks:latest
script:
- aws eks update-kubeconfig --name=sandbox
- git clone --branch=master https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/minds/helm-charts.git
- "helm upgrade \
--install \
--reuse-values \
--set frontInit.image.repository=$CI_REGISTRY_IMAGE/front-init \
--set-string frontInit.image.tag=$CI_PIPELINE_ID \
--set domain=$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN \
--set elasticsearch.clusterName=$CI_BUILD_REF_SLUG--elasticsearch \
--wait \
$CI_BUILD_REF_SLUG \
./helm-charts/minds"
# Update sentry
- sentry-cli releases deploys $CI_PIPELINE_ID new -e review-$CI_COMMIT_REF_SLUG
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
on_stop: review:stop
except:
refs:
- master
- test/gitlab-ci
review:stop:
<<: *cleanup_review
stage: review
when: manual
################
# Deploy Stage #
################
.deploy: &deploy
image: minds/ci:latest
services:
- docker:dind
script:
## Sync assets with CDN
- aws s3 sync dist $S3_REPOSITORY_URL
- $(aws ecr get-login --no-include-email --region us-east-1)
## Update docker front-init container
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker pull $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID
- docker tag $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID $ECR_REPOSITORY_URL:$IMAGE_LABEL
- docker push $ECR_REPOSITORY_URL:$IMAGE_LABEL
## Deploy the new container in rolling restart
- aws ecs update-service --service=$ECS_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
## Update sentry
- sentry-cli releases deploys $CI_PIPELINE_ID new -e $IMAGE_LABEL
dependencies:
- build:production:en
- build:production:i18n
only:
refs:
- master
- test/gitlab-ci
staging:fpm:
<<: *deploy
stage: deploy:staging
variables:
IMAGE_LABEL: 'staging'
ECS_SERVICE: $ECS_APP_STAGING_SERVICE
environment:
name: staging
url: https://www.minds.com # requires staging cookie
deploy:canary:
<<: *deploy
stage: deploy:canary
variables:
IMAGE_LABEL: 'canary'
ECS_SERVICE: $ECS_APP_CANARY_SERVICE
environment:
name: canary
url: https://www.minds.com/?canary=1 # requires canary cookie
when: manual
allow_failure: false # prevents auto deploy to full production
deploy:production:
<<: *deploy
stage: deploy:production
variables:
IMAGE_LABEL: 'production'
ECS_SERVICE: $ECS_APP_PRODUCTION_SERVICE
environment: environment:
name: production name: production
url: https://www.minds.com
when: delayed
start_in: 12 hours # reduce? can always be deployed manually earlier too
#################
# Cleanup stage #
#################
cleanup:review: # We stop the review site after the e2e tests have run
<<: *cleanup_review
stage: cleanup
when: manual
except:
refs:
- master
- test/gitlab-ci
### Summary
(What is the Merge request intending to do, in plain language)
(Be sure to associate any related issues or merge requests)
### Steps to test
(Steps to demonstrate merge achieves goal)
(Include any platform specific directions)
### Estimated Regression Scope
(What features do these changes effect in your estimation?)
# .prettierrc
# Use this file to define your defaults for prettier
# For a list of all available options:
# https://prettier.io/docs/en/options.html
trailingComma: 'es5'
printWidth: 80
singleQuote: true
semi: true
...@@ -6,7 +6,7 @@ Minds Front ...@@ -6,7 +6,7 @@ Minds Front
Front-end web application for Minds. Please run inside of [the Minds repo](https://github.com/minds/minds). Front-end web application for Minds. Please run inside of [the Minds repo](https://github.com/minds/minds).
## Documentation ## Documentation
Documentation for Minds can be found at [minds.org/docs](https://www.minds.org/docs) Please see the documentation on [developers.minds.com](https://developers.minds.com) for instructions on how to [build the Minds Front-end](https://developers.minds.com/docs/guides/frontend).
### Building ### Building
Please see the documentation on Minds.org for instructions on how to [build the Minds Front-end](https://www.minds.org/docs/install/preparation.html#front-end). Please see the documentation on Minds.org for instructions on how to [build the Minds Front-end](https://www.minds.org/docs/install/preparation.html#front-end).
......
...@@ -17,19 +17,16 @@ ...@@ -17,19 +17,16 @@
"tsConfig": "src/tsconfig.app.json", "tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"extractCss": true, "extractCss": true,
"assets": [ "assets": ["src/assets", "src/favicon.ico"],
"src/assets",
"src/favicon.ico"
],
"styles": [ "styles": [
"node_modules/material-design-lite/dist/material.blue_grey-amber.min.css", "node_modules/material-design-lite/dist/material.blue_grey-amber.min.css",
"node_modules/plyr/dist/plyr.css",
"node_modules/material-design-icons/iconfont/material-icons.css", "node_modules/material-design-icons/iconfont/material-icons.css",
"src/main.css" "src/main.css"
], ],
"scripts": [ "scripts": [
"node_modules/material-design-lite/dist/material.min.js", "node_modules/material-design-lite/dist/material.min.js",
"node_modules/medium-editor/dist/js/medium-editor.min.js", "node_modules/medium-editor/dist/js/medium-editor.min.js",
"src/shims/fontawesome.js",
"src/shims/jitsi-api.min.js" "src/shims/jitsi-api.min.js"
] ]
}, },
...@@ -37,7 +34,11 @@ ...@@ -37,7 +34,11 @@
"production": { "production": {
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": false, "sourceMap": {
"hidden": true,
"scripts": true,
"styles": true
},
"extractCss": true, "extractCss": true,
"namedChunks": false, "namedChunks": false,
"aot": true, "aot": true,
...@@ -50,6 +51,14 @@ ...@@ -50,6 +51,14 @@
"with": "src/environments/environment.prod.ts" "with": "src/environments/environment.prod.ts"
} }
] ]
},
"hmr": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.hmr.ts"
}
]
} }
} }
}, },
...@@ -61,6 +70,10 @@ ...@@ -61,6 +70,10 @@
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "v5.x:build:production" "browserTarget": "v5.x:build:production"
},
"hmr": {
"hmr": true,
"browserTarget": "v5.x:build:hmr"
} }
} }
}, },
...@@ -79,25 +92,16 @@ ...@@ -79,25 +92,16 @@
"scripts": [ "scripts": [
"node_modules/material-design-lite/dist/material.min.js", "node_modules/material-design-lite/dist/material.min.js",
"node_modules/medium-editor/dist/js/medium-editor.min.js", "node_modules/medium-editor/dist/js/medium-editor.min.js",
"src/shims/fontawesome.js",
"src/shims/jitsi-api.min.js" "src/shims/jitsi-api.min.js"
], ],
"assets": [ "assets": ["src/assets", "src/favicon.ico"]
"src/assets",
"src/favicon.ico"
]
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-devkit/build-angular:tslint",
"options": { "options": {
"tsConfig": [ "tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"],
"src/tsconfig.app.json", "exclude": ["**/node_modules/**"]
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
} }
}, },
"server": { "server": {
...@@ -133,12 +137,8 @@ ...@@ -133,12 +137,8 @@
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-devkit/build-angular:tslint",
"options": { "options": {
"tsConfig": [ "tsConfig": ["e2e/tsconfig.e2e.json"],
"e2e/tsconfig.e2e.json" "exclude": ["**/node_modules/**"]
],
"exclude": [
"**/node_modules/**"
]
} }
} }
} }
...@@ -147,11 +147,11 @@ ...@@ -147,11 +147,11 @@
"defaultProject": "v5.x", "defaultProject": "v5.x",
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
"prefix": "app", "prefix": "m",
"styleext": "scss" "styleext": "scss"
}, },
"@schematics/angular:directive": { "@schematics/angular:directive": {
"prefix": "app" "prefix": "m"
} }
} }
} }
#!/bin/sh #!/bin/sh
ng build --prod --vendor-chunk --output-path="$1/en/" --deploy-url="$2/en/" --build-optimizer=false --source-map=false export NODE_OPTIONS="--max-old-space-size=3584"
ng build --prod --vendor-chunk --output-path="$1/en/" --deploy-url="$2/en/" --build-optimizer=false
#!/bin/sh #!/bin/sh
export NODE_OPTIONS="--max-old-space-size=3584"
do_locale_build () { do_locale_build () {
ng build --prod --vendor-chunk --output-path="$2/$1/" --deploy-url="$3/$1/" --build-optimizer=false --source-map=false \ ng build --prod --vendor-chunk --output-path="$2/$1/" --deploy-url="$3/$1/" --build-optimizer=false --source-map=false \
......
FROM alpine:edge
COPY . dist
## Hack to make initial laguage load
COPY en/index.php dist/index.php
\ No newline at end of file
{} {
"projectId": "qrjqcv",
"requestTimeout": 3600000,
"responseTimeout": 3600000,
"pageLoadTimeout": 3600000
}
#!/usr/bin/env bash
# Boilerplate generated with create-bash-script (c) 2019 Nikita Skobov
# Available https://github.com/nikita-skobov/create-bash-script
function usage()
{
local just_help=$1
local missing_required=$2
local invalid_argument=$3
local invalid_option=$4
local help="Usage: e2e.sh [OPTIONS]
Intended to serve as an interaction wrapper around Cypress. Ensure that you run from within the project.
Example: ./e2e.sh -u nemofin -p password123 -v true -h http://www.minds.com/
Options (* indicates it is required):"
local help_options="
*\-p ,\--password \<Parameter>\ The password of the user.
\-h ,\--url \<Parameter>\ The URL of the host e.g. https://www.minds.com/ - defaults to use localhost.
\-u ,\--username \<Parameter>\ The username - defaults to cypress_e2e_test.
\-pu ,\--pro_username \<Parameter>\ The pro users username.
\-pp ,\--pro_password \<Parameter>\ The pro users password
\-v ,\---video \<Parameter>\ true if you want video providing.
\-e, \--env \<Parameter>\ add additional env variables e.g. production=true
"
if [ "$missing_required" != "" ]
then
echo "Missing required argument: $missing_required"
fi
if [ "$invalid_option" != "" ] && [ "$invalid_value" = "" ]
then
echo "Invalid option: $invalid_option"
elif [ "$invalid_value" != "" ]
then
echo "Invalid value: $invalid_value for option: --$invalid_option"
fi
echo -e "
"
echo "$help"
echo "$help_options" | column -t -s'\'
return
}
function init_args()
{
REQ_ARGS=( "password" )
# get command line arguments
POSITIONAL=()
# set default arguments
url="http://localhost"
username="minds_cypress_tests"
pro_username="minds_pro_cypress_tests"
pro_password=""
env=""
_video=false
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-h|--url)
url="$2"
shift 2
;;
-u|--username)
username="$2"
shift 2
;;
-p|--password)
password="$2"
shift 2
;;
-v|--video)
_video="$2"
shift 2
;;
-pu|--pro-username)
pro_username="$2"
shift 2
;;
-pp|--pro-password)
pro_password="$2"
shift 2
;;
-e|--env)
env=",$2"
shift 2
;;
*)
POSITIONAL+=("$1") # saves unknown option in array
shift
;;
esac
done
for i in "${REQ_ARGS[@]}"; do
# $i is the string of the variable name
# ${!i} is a parameter expression to get the value
# of the variable whose name is i.
req_var=${!i}
if [ "$req_var" = "" ]
then
usage "" "--$i"
exit
fi
done
}
init_args $@
# cd to project root.
while [[ $PWD != '/' && ${PWD##*/} != 'front' ]]; do cd ..; done
#run cypress with args.
echo $(npm bin)/cypress open --config baseUrl=$url,video=$_video --env username=$username,password=$password,pro_username=$pro_username,pro_password=$pro_password$env $POSITIONAL
$(npm bin)/cypress open --config baseUrl=$url,video=$_video --env username=$username,password=$password,pro_username=$pro_username,pro_password=$pro_password$env $POSITIONAL
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
context('Rewards Product Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
});
const joinRewards = '.m-marketing__mainWrapper .mf-button';
it('should have a join rewards button', () => {
cy.visit('/rewards');
cy.get(joinRewards)
.should('be.visible')
.should('contain', 'Join Rewards')
.click();
cy.location('pathname').should(
'contains',
'/wallet/tokens/contributions'
);
});
});
context('Token Page', () => {
before(() => {
cy.getCookie('minds_sess').then(sessionCookie => {
if (!sessionCookie) {
return cy.login(true);
}
});
});
beforeEach(() => {
cy.preserveCookies();
cy.visit('/token');
});
it('should have the ability to trigger Buy Tokens modal', () => {
const tokensInput = 'm-blockchain--purchase input[name=amount]';
const buyTokensButton =
'm-blockchain--purchase .m-blockchainTokenPurchase__action .mf-button';
const anyBuyTokensModal =
'm-blockchain--purchase m-modal .m-modal-container';
cy.get(tokensInput)
.focus()
.clear()
.type('0');
cy.get(buyTokensButton).should('be.disabled');
cy.get(tokensInput)
.focus()
.clear()
.type('1');
cy.get(buyTokensButton)
.should('not.be.disabled')
.click();
cy.get('.m-get-metamask--cancel-btn.m-btn').click();
cy.get(anyBuyTokensModal).should('be.visible');
});
it('should have the ability to trigger Buy Eth modal', () => {
const buyEthLink =
'm-blockchain--purchase .m-blockchainTokenPurchase__ethRate a';
const buyEthModal = 'm-blockchain__eth-modal .m-modal-container';
cy.get(buyEthLink).click();
cy.get(buyEthModal).should('be.visible');
});
});
context('Blogs', () => { // import 'cypress-file-upload';
beforeEach(() => {
cy.login(true);
cy.location('pathname').should('eq', `/newsfeed/subscriptions`);
})
it('should not be able to create a new blog if no title or banner are specified', () => {
cy.visit('/blog/edit/new');
cy.get('.m-button--submit').click(); context('Blogs', () => {
cy.wait(100); const closeButton = '[data-cy=data-minds-conversation-close]';
cy.get('.m-blog--edit--error').contains('Error: You must provide a title'); before(() => {
cy.getCookie('minds_sess')
.then((sessionCookie) => {
if (sessionCookie === null) {
return cy.login(true);
}
});
// ensure no messenger windows are open.
cy.get('body').then(($body) => {
if ($body.find(closeButton).length) {
cy.get(closeButton)
.click({multiple: true});
}
});
});
cy.get('minds-textarea .m-editor').type('Title'); beforeEach(() => {
cy.preserveCookies();
cy.server();
cy.route('POST', '**/api/v1/blog/new').as('postBlog');
cy.route('POST', '**/api/v1/media**').as('postMedia');
cy.route('GET', '**/api/v1/blog/**').as('getBlog');
cy.route('DELETE', '**/api/v1/blog/**').as('deleteBlog');
cy.visit('/newsfeed/global/top')
.location('pathname')
.should('eq', '/newsfeed/global/top');
});
cy.get('.m-button--submit').click(); const uploadAvatar = () => {
cy.visit(`/${Cypress.env().username}`);
cy.get('.m-channel--name .minds-button-edit button:first-child').click();
cy.uploadFile(
'.minds-avatar input[type=file]',
'../fixtures/avatar.jpeg',
'image/jpg'
);
cy.get('.m-channel--name .minds-button-edit button:last-child').click();
};
cy.get('.m-blog--edit--error').contains('Error: You must upload a banner'); const createBlogPost = (title, body, nsfw = false, schedule = false) => {
})
it('should be able to create a new blog', () => {
cy.visit('/blog/edit/new'); cy.visit('/blog/edit/new');
cy.uploadFile('minds-banner #file', '../fixtures/international-space-station-1776401_1920.jpg', 'image/jpg'); cy.uploadFile(
'.minds-banner input[type=file]',
'../fixtures/international-space-station-1776401_1920.jpg',
'image/jpg'
);
cy.get('minds-textarea .m-editor').type('Title'); cy.get('minds-textarea .m-editor').type(title);
cy.get('m-inline-editor .medium-editor-element').type(body);
cy.get('m-inline-editor .medium-editor-element').type('Content\n');
// click on plus button // // click on plus button
cy.get('.medium-editor-element > .medium-insert-buttons > button.medium-insert-buttons-show').click(); // cy.get('.medium-editor-element > .medium-insert-buttons > button.medium-insert-buttons-show').click();
// click on camera // // click on camera
cy.get('ul.medium-insert-buttons-addons > li > button.medium-insert-action:first-child').contains('photo_camera').click(); // cy.get('ul.medium-insert-buttons-addons > li > button.medium-insert-action:first-child').contains('photo_camera').click();
// upload the image // upload the image
cy.uploadFile('.medium-media-file-input', '../fixtures/international-space-station-1776401_1920.jpg', 'image/jpg'); cy.uploadFile('.medium-media-file-input', '../fixtures/international-space-station-1776401_1920.jpg', 'image/jpg')
.wait('@postMedia').then(xhr => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
});
// open license dropdown & select first license // open license dropdown & select first license
cy.get('.m-license-info select').select('All rights reserved'); cy.get('.m-license-info select').select('All rights reserved');
// click on hashtags dropdown // click on hashtags dropdown
cy.get('.m-category-info m-hashtags-selector .m-dropdown--label-container').click(); cy.get(
'.m-category-info m-hashtags-selector .m-dropdown--label-container'
).click();
// select #ART // select #ART
cy.get('.m-category-info m-dropdown m-form-tags-input > div:nth-child(1) > span').contains('#art').click(); cy.get('.m-category-info m-dropdown m-form-tags-input > div > span')
.contains('#art')
.click();
// type in another hashtag manually // type in another hashtag manually
cy.get('.m-category-info m-hashtags-selector m-form-tags-input input').type('hashtag{enter}').click(); cy.get('.m-category-info m-hashtags-selector m-form-tags-input input')
.type('hashtag{enter}')
.click();
// click away // click away
cy.get('.m-category-info m-hashtags-selector .minds-bg-overlay').click(); cy.get('.m-category-info m-hashtags-selector .minds-bg-overlay').click();
...@@ -57,39 +92,232 @@ context('Blogs', () => { ...@@ -57,39 +92,232 @@ context('Blogs', () => {
cy.get('.m-visibility-info select').select('Loggedin'); cy.get('.m-visibility-info select').select('Loggedin');
// open metadata form // open metadata form
cy.get('.m-blog-edit--toggle-wrapper .m-blog-edit--toggle').contains('Metadata').click(); cy.get('.m-blog-edit--toggle-wrapper .m-blog-edit--toggle')
.contains('Metadata')
.click();
// set url slug // set url slug
cy.get('.m-blog-edit--field input[name=slug]').type('123'); cy.get('.m-blog-edit--field input[name=slug]').type('123');
// set meta title // set meta title
cy.get('.m-blog-edit--field input[name=custom_meta_title]').type('Test'); cy.get('.m-blog-edit--field input[name=custom_meta_title]').type('Test');
// set meta description // set meta description
cy.get('.m-blog-edit--field textarea[name=custom_meta_description]').type('This is a test blog'); cy.get('.m-blog-edit--field textarea[name=custom_meta_description]').type(
'This is a test blog'
);
// set meta author // set meta author
cy.get('.m-blog-edit--field input[name=custom_meta_author]').type('Minds Test'); cy.get('.m-blog-edit--field input[name=custom_meta_author]').type(
'Minds Test'
);
// set as nsfw if (nsfw) {
cy.get('.m-mature-info a').click(); // click on nsfw dropdown
cy.get('.m-mature-info a span').contains('Mature content'); cy.get(
'm-nsfw-selector .m-dropdown--label-container'
).click();
cy.wait(1000); // select Nudity
cy.get('m-nsfw-selector .m-dropdownList__item')
.contains('Nudity')
.click();
cy.get('.m-button--submit').click(); // click away
cy.get('m-nsfw-selector .minds-bg-overlay').click({force: true});
cy.wait(100); }
cy.location('pathname').should('contains', `/${Cypress.env().username}/blog`); if (schedule) {
cy.get('.m-poster-date-selector__input').click();
cy.get(
'td.c-datepicker__day-body.c-datepicker__day--selected + td'
).click();
cy.get('a.c-btn.c-btn--flat.js-ok').click();
cy.get('.m-blog--title').contains('Title'); // get setted date to compare
cy.get('.minds-blog-body p').contains('Content'); let scheduledDate;
cy.get('div.m-poster-date-selector__input div.m-tooltip--bubble')
.invoke('text')
.then(text => {
scheduledDate = text;
});
}
cy.get('.m-button--submit')
.click({ force: true }) // TODO: Investigate why disabled flag is being detected
.wait('@postBlog').then(xhr => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
})
.wait('@getBlog').then(xhr => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
expect(xhr.response.body).to.have.property('blog');
});
cy.location('pathname')
.should('contains', `/${Cypress.env().username}/blog`);
cy.get('.m-blog--title').contains(title);
cy.get('.minds-blog-body p').contains(body);
cy.get('.m-license-info span').contains('all-rights-reserved'); cy.get('.m-license-info span').contains('all-rights-reserved');
// cleanup if (schedule) {
cy.wait(1000);
cy.get('div.m-blog-container div.mdl-grid div.minds-body span')
.invoke('text')
.then(text => {
const time_created = new Date(text).getTime();
scheduledDate = new Date(scheduledDate).getTime();
expect(scheduledDate).to.equal(time_created);
});
}
};
//open dropdown const deleteBlogPost = () => {
cy.get('m-post-menu button.minds-more').click(); cy.get('m-post-menu button.minds-more').click();
cy.get('m-post-menu ul.minds-dropdown-menu li:nth-child(3)').contains('Delete').click(); cy.get('m-post-menu ul.minds-dropdown-menu li')
.contains('Delete')
.click();
cy.get('m-post-menu m-modal-confirm .mdl-button--colored').click(); cy.get('m-post-menu m-modal-confirm .mdl-button--colored').click();
cy.wait('@deleteBlog').then(xhr => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
});
};
const editBlogPost = (title, body) => {
cy.location('pathname').should(
'contains',
`/${Cypress.env().username}/blog`
);
cy.get('m-post-menu').click();
cy.get('.minds-dropdown-menu li')
.first()
.click();
cy.location('pathname').should('contains', '/blog/edit');
cy.get('minds-textarea .m-editor').type(title);
cy.get('m-inline-editor .medium-editor-element').type(body);
cy.get('.m-button--submit').click();
cy.wait('@postBlog').then(xhr => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
cy.wait('@getBlog').then(xhr => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
expect(xhr.response.body).to.have.property('blog');
});
});
cy.location('pathname').should(
'contains',
`/${Cypress.env().username}/blog`
);
cy.get('.m-blog--title').contains(title);
cy.get('.minds-blog-body p').contains(body);
};
it('should not be able to create a new blog if no title or banner are specified', () => {
cy.visit('/blog/edit/new');
cy.get('.m-button--submit').click();
cy.get('.m-blog--edit--error').contains('Error: You must provide a title');
cy.get('minds-textarea .m-editor').type('Title');
cy.get('.m-button--submit').click();
cy.get('.m-blog--edit--error').contains('Error: You must upload a banner');
});
it('should be able to create a new blog', () => {
const title = 'Title';
const body = 'Content';
uploadAvatar();
createBlogPost(title, body, true);
deleteBlogPost();
});
/**
* Skipping until the scheduling options are visible on sandboxes
* currently they are not, missing setting perhaps?
*/
it.skip('should be able to create a new scheduled blog', () => {
uploadAvatar();
createBlogPost('Title', 'Content', true, true);
deleteBlogPost();
});
/**
* Skipping until sandbox behaves consistently as currently when posting,
* on the sandbox it does not update the newsfeed and channel straight away as it does on prod.
*/
it.skip('should create an activity for the blog post', () => {
const identifier = Math.floor(Math.random() * 100);
const title = 'Test Post for Activity ' + identifier;
const body = 'Some content here ' + identifier;
createBlogPost(title, body);
cy.visit(`/${Cypress.env().username}`);
//:nth-child(3) > .mdl-card > .m-rich-embed > minds-rich-embed > .m-rich-embed-src > .meta > .m-rich-embed--title
cy.get('minds-activity:first .m-blurb').contains(body);
cy.get('minds-activity:first .m-rich-embed--title')
.first()
.contains(title);
cy.get('minds-activity:first .thumbnail')
.should('have.attr', 'href')
.then(href => {
cy.visit(href);
});
cy.location('pathname').should(
'contains',
`/${Cypress.env().username}/blog`
);
deleteBlogPost();
cy.location('pathname').should(
'contains',
`/blog/owner`
);
});
/**
* Skipping until sandbox behaves consistently as currently when posting,
* on the sandbox it does not update the newsfeed and channel straight away as it does on prod.
*/
it.skip('should update the activity when blog is updated', () => {
const identifier = Math.floor(Math.random() * 100);
const title = 'Test Post for Activity ' + identifier;
const body = 'Some content here ' + identifier;
createBlogPost(title, body);
cy.visit(`/${Cypress.env().username}`);
cy.get('minds-activity:first .m-blurb').contains(body);
cy.get('minds-activity:first .m-rich-embed--title')
.first()
.contains(title);
cy.get('minds-activity:first .thumbnail')
.should('have.attr', 'href')
.then(href => {
cy.visit(href);
});
const newtitle = title + ' changed';
const newbody = body + ' changed';
editBlogPost(newtitle, newbody);
cy.visit(`/${Cypress.env().username}`);
cy.get('minds-activity:first .m-blurb').contains(body);
cy.get('minds-activity:first .m-rich-embed--title')
.first()
.contains(title);
}) cy.get('minds-activity:first .thumbnail')
}) .should('have.attr', 'href')
.then(href => {
cy.visit(href);
});
deleteBlogPost();
});
});
/**
* @author Ben Hayward
* @desc E2E testing for Minds Boost Console pages.
*/
import generateRandomId from '../../support/utilities';
context('Boost Console', () => {
const postContent = "Test boost, please reject..." + generateRandomId();
before(() => {
cy.getCookie('minds_sess')
.then((sessionCookie) => {
if (sessionCookie === null) {
return cy.login(true);
}
});
newBoost(postContent, 500);
});
beforeEach(() => {
cy.preserveCookies();
cy.server();
cy.route("POST", '**/api/v2/boost/**').as('boostPost');
cy.visit('/boost/console/newsfeed/history');
});
it('should show a new boost in the console', () => {
cy.get('m-boost-console-card:nth-child(1) div.m-boost-card--manager-item.m-boost-card--state')
.should('not.contain', 'revoked');
cy.get('m-boost-console-card:nth-child(1) .m-mature-message span')
.contains(postContent);
});
it('should allow a revoke a boost', () => {
cy.get('m-boost-console-card:nth-child(1) div.m-boost-card--manager-item.m-boost-card--state')
.should('not.contain', 'revoked');
cy.get('m-boost-console-card:nth-child(1) .m-boost-card--manager-item--buttons > button')
.click();
cy.get('m-boost-console-card:nth-child(1) div.m-boost-card--manager-item.m-boost-card--state')
.contains('revoked');
});
it('should load show the user content for newsfeed boosts', () => {
cy.route("GET", "**/feeds/container/*/activities**").as("activities");
cy.contains('Create a Boost')
.click()
.location('pathname')
.should('eq', `/boost/console/newsfeed/create`)
.wait('@activities').then((xhr) => {
expect(xhr.status).to.equal(200);
});
})
it('should load show the user content for sidebar boosts', () => {
cy.route("GET", "**/api/v2/feeds/container/*/all**").as("all");
cy.visit('/boost/console/content/create')
.location('pathname')
.should('eq', `/boost/console/content/create`)
.wait('@all').then((xhr) => {
expect(xhr.status).to.equal(200);
});
})
it('should load show the user content for offers', () => {
cy.route("GET", "**/api/v2/feeds/container/*/activities**").as("all");
cy.visit('/boost/console/offers/create')
.location('pathname')
.should('eq', `/boost/console/offers/create`)
.wait('@all').then((xhr) => {
expect(xhr.status).to.equal(200);
});
})
function newBoost(text, views) {
cy.server();
cy.route("POST", '**/api/v2/boost/**').as('boostPost');
cy.visit('/newsfeed/subscribed');
cy.post(text);
cy.get('#boost-actions')
.first()
.click();
cy.get('.m-boost--creator-section-amount input')
.type(views);
cy.get('m-overlay-modal > div.m-overlay-modal > m-boost--creator button')
.click();
cy.wait('@boostPost').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.deep.equal("success");
});
cy.get('.m-overlay-modal')
.should('not.be.visible')
}
})
/**
* @author Ben Hayward
* @desc E2E testing for Minds Boost Console pages.
*/
import generateRandomId from '../../support/utilities';
context('Boost Console', () => {
const postContent = "Test boost, please reject..." + generateRandomId();
before(() => {
cy.getCookie('minds_sess')
.then((sessionCookie) => {
if (sessionCookie === null) {
return cy.login(true);
}
});
newBoost(postContent, 500);
});
beforeEach(() => {
cy.server();
cy.route("POST", '**/api/v2/boost/**').as('boostPost');
cy.preserveCookies();
cy.visit('/boost/console/newsfeed/history');
});
after(() => {
cy.clearCookies();
});
it('should show a new boost in the console', () => {
cy.get('m-boost-console-card:nth-child(1) div.m-boost-card--manager-item.m-boost-card--state')
.should('not.contain', 'revoked');
cy.get('m-boost-console-card:nth-child(1) .m-mature-message span')
.contains(postContent);
});
it('should allow a revoke a boost', () => {
cy.get('m-boost-console-card:nth-child(1) div.m-boost-card--manager-item.m-boost-card--state')
.should('not.contain', 'revoked');
cy.get('m-boost-console-card:nth-child(1) .m-boost-card--manager-item--buttons > button')
.click();
cy.get('m-boost-console-card:nth-child(1) div.m-boost-card--manager-item.m-boost-card--state')
.contains('revoked');
});
it('should load show the user content for newsfeed boosts', () => {
cy.route("GET", "**/feeds/container/*/activities**").as("activities");
cy.contains('Create a Boost')
.click()
.location('pathname')
.should('eq', `/boost/console/newsfeed/create`)
.wait('@activities').then((xhr) => {
expect(xhr.status).to.equal(200);
});
})
it('should load show the user content for sidebar boosts', () => {
cy.route("GET", "**/api/v2/feeds/container/*/all**").as("all");
cy.visit('/boost/console/content/create')
.location('pathname')
.should('eq', `/boost/console/content/create`)
.wait('@all').then((xhr) => {
expect(xhr.status).to.equal(200);
});
})
it('should load show the user content for offers', () => {
cy.route("GET", "**/api/v2/feeds/container/*/activities**").as("all");
cy.visit('/boost/console/offers/create')
.location('pathname')
.should('eq', `/boost/console/offers/create`)
.wait('@all').then((xhr) => {
expect(xhr.status).to.equal(200);
});
})
function newBoost(text, views) {
cy.server();
cy.route("POST", '**/api/v2/boost/**').as('boostPost');
cy.visit('/newsfeed/subscribed');
cy.post(text);
cy.get('#boost-actions')
.first()
.click();
cy.get('.m-boost--creator-section-amount input')
.type(views);
cy.get('m-overlay-modal > div.m-overlay-modal > m-boost--creator button')
.click();
cy.wait('@boostPost').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.deep.equal("success");
});
cy.get('.m-overlay-modal')
.should('not.be.visible')
}
})
// Cannot test until env behaves consistently else,
// the test will frequently error when it cant see a boost.
context.skip('Boost Impressions', () => {
before(() => {
cy.getCookie('minds_sess')
.then((sessionCookie) => {
if (sessionCookie === null) {
return cy.login(true);
}
});
});
beforeEach(()=> {
cy.server();
cy.route("POST", "**api/v2/analytics/views/boost/*").as("analytics");
cy.route("GET", "**/api/v2/feeds/subscribed/activities**").as("activities");
cy.preserveCookies();
cy.visit('/newsfeed/subscriptions')
.location('pathname')
.should('eq', `/newsfeed/subscriptions`)
.wait('@activities').then((xhr) => {
expect(xhr.status).to.equal(200);
});
});
afterEach(()=> {
cy.reload();
})
it('should register views on scroll', () => {
//smooth scroll
cy.scrollTo('0', '1%', { duration: 100 });
//assert
cy.wait('@analytics').then((xhr) => {
expect(xhr.status).to.equal(200);
});
});
it('should register views on boost rotate', () => {
//rotate forward and wait to trigger analytics
cy.get('m-newsfeed--boost-rotator')
.find('chevron_right')
.click();
//assert
cy.wait('@analytics').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.deep.equal("success");
});
//rotate forward and wait to trigger analytics
cy.get('m-newsfeed--boost-rotator')
.find('chevron_left')
.click();
//assert
cy.wait('@analytics').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.deep.equal("success");
});
});
});