Signed-off-by: Louis Chemineau <louis@chmn.me>
This commit is contained in:
Louis Chemineau 2021-04-29 19:44:06 +02:00 коммит произвёл Louis
Родитель 44c6367b20
Коммит 4fe5aef4c9
29 изменённых файлов: 6807 добавлений и 1050 удалений

2
.gitattributes поставляемый
Просмотреть файл

@ -1,3 +1,5 @@
js/dist/activity-sidebar.js binary
js/dist/*.LICENCE.map binary
js/dist/*.js.map binary
package-lock.json binary
src/test/__snapshots__/*.snap

69
.github/workflows/cypress.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,69 @@
name: Cypress
on: [push]
env:
APP_NAME: activity
CYPRESS_baseUrl: http://localhost:8081/index.php
BRANCH: ${{ github.base_ref }}
PHP_VERSION: 7.4
jobs:
cypress:
name: cypress ${{ matrix.node-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [12.x]
# containers: [1, 2, 3]
steps:
- name: Checkout server
uses: actions/checkout@v2
with:
repository: nextcloud/server
submodules: true
ref: ${{ env.BRANCH }}
- name: Checkout ${{ env.APP_NAME }}
uses: actions/checkout@v2
with:
path: apps/${{ env.APP_NAME }}
- name: Set up php ${{ env.PHP_VERSION }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ env.PHP_VERSION }}
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, zip, gd, apcu
coverage: none
- name: Set up Nextcloud
env:
DB_PORT: 4444
PHP_CLI_SERVER_WORKERS: 10
run: |
mkdir data
php occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php occ config:system:set memcache.local --value="\\OC\\Memcache\\APCu"
php -f index.php
php -S 0.0.0.0:8081 &
export OC_PASS=1234561
php occ user:add --password-from-env user1
php occ user:add --password-from-env user2
php occ config:system:set force_language --value en
php occ app:enable activity
php occ app:list
curl -v http://localhost:8081/index.php/login
cat data/nextcloud.log
- name: Cypress run
uses: cypress-io/github-action@v2
with:
record: false # disabled for now as we have no way to savely use the token in our org
parallel: false
wait-on: '${{ env.CYPRESS_baseUrl }}'
working-directory: 'apps/${{ env.APP_NAME }}'
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}

34
.github/workflows/node.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,34 @@
name: Node
on:
pull_request:
push:
branches:
- master
- stable*
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12]
name: node${{ matrix.node-version }}
steps:
- uses: actions/checkout@v2
- name: Set up node ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies & build
run: |
npm ci
npm run build --if-present
- name: Check webpack build changes
run: |
bash -c "[[ ! \"`git status --porcelain `\" ]] || ( echo 'Uncommited changes in webpack build' && git status && exit 1 )"

31
.github/workflows/npm-test.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,31 @@
name: Test
on:
pull_request:
push:
branches:
- master
- stable*
jobs:
jest:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12]
name: node${{ matrix.node-version }}
steps:
- uses: actions/checkout@v2
- name: Set up node ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Test
run: npm run test

5
.gitignore поставляемый
Просмотреть файл

@ -64,4 +64,7 @@ nbproject
# Vue.js
/build/
node_modules/
js/*hot-update.*
js/*hot-update.*
coverage
cypress/screenshots/
cypress/videos/

Просмотреть файл

@ -0,0 +1,584 @@
{
"ocs": {
"meta": {
"status": "ok",
"statuscode": 200,
"message": "OK"
},
"data": [
{
"activity_id": 25,
"app": "comments",
"type": "comments",
"user": "admin",
"subject": "You commented",
"subject_rich": [
"You commented",
[]
],
"message": "zerzer",
"message_rich": [
"zerzer",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "",
"objects": {
"776": ""
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/comment.svg",
"datetime": "2021-04-29T13:57:11+00:00"
},
{
"activity_id": 23,
"app": "files",
"type": "file_changed",
"user": "admin",
"subject": "You renamed Test file - renamed.md to Test file - renamed - looooooooong.md",
"subject_rich": [
"You renamed {oldfile} to {newfile}",
{
"newfile": {
"type": "file",
"id": "776",
"name": "Test file - renamed - looooooooong.md",
"path": "Test file - renamed - looooooooong.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
},
"oldfile": {
"type": "file",
"id": "776",
"name": "Test file - renamed.md",
"path": "Test file - renamed.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/\/Test file - renamed - looooooooong.md",
"objects": {
"776": "\/\/Test file - renamed - looooooooong.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/",
"icon": "http:\/\/localhost:8080\/apps\/files\/img\/change.svg",
"datetime": "2021-04-29T09:12:46+00:00"
},
{
"activity_id": 22,
"app": "comments",
"type": "comments",
"user": "admin",
"subject": "You commented",
"subject_rich": [
"You commented",
[]
],
"message": "An edited comment",
"message_rich": [
"An edited comment",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "",
"objects": {
"776": ""
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/comment.svg",
"datetime": "2021-04-29T09:05:01+00:00"
},
{
"activity_id": 21,
"app": "comments",
"type": "comments",
"user": "admin",
"subject": "You commented",
"subject_rich": [
"You commented",
[]
],
"message": "A veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery long and useleeeeeeeeeeeeeeees comment",
"message_rich": [
"A veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery long and useleeeeeeeeeeeeeeees comment",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "",
"objects": {
"776": ""
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/comment.svg",
"datetime": "2021-04-29T09:04:56+00:00"
},
{
"activity_id": 20,
"app": "comments",
"type": "comments",
"user": "admin",
"subject": "You commented",
"subject_rich": [
"You commented",
[]
],
"message": "A comment",
"message_rich": [
"A comment",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "",
"objects": {
"776": ""
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/comment.svg",
"datetime": "2021-04-29T09:04:43+00:00"
},
{
"activity_id": 19,
"app": "files",
"type": "favorite",
"user": "admin",
"subject": "Added to favorites",
"subject_rich": [
"",
[]
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "Test file - renamed.md",
"objects": {
"776": "Test file - renamed.md"
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/starred.svg",
"datetime": "2021-04-29T08:52:19+00:00"
},
{
"activity_id": 18,
"app": "files",
"type": "unfavorite",
"user": "admin",
"subject": "Removed from favorites",
"subject_rich": [
"",
[]
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "Test file - renamed.md",
"objects": {
"776": "Test file - renamed.md"
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/star.svg",
"datetime": "2021-04-29T08:52:07+00:00"
},
{
"activity_id": 15,
"app": "files",
"type": "file_changed",
"user": "admin",
"subject": "You changed Test file - renamed.md",
"subject_rich": [
"You changed {file1}",
{
"file1": {
"type": "file",
"id": "776",
"name": "Test file - renamed.md",
"path": "Test file - renamed.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/Test file - renamed.md",
"objects": {
"776": "\/Test file - renamed.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/",
"icon": "http:\/\/localhost:8080\/apps\/files\/img\/change.svg",
"datetime": "2021-04-29T08:51:42+00:00"
},
{
"activity_id": 14,
"app": "systemtags",
"type": "systemtags",
"user": "admin",
"subject": "Added system tag 2gat",
"subject_rich": [
"Added system tag {systemtag}",
{
"systemtag": {
"type": "systemtag",
"id": 2,
"name": "2gat",
"assignable": "1",
"visibility": "1"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "",
"objects": {
"776": ""
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/tag.svg",
"datetime": "2021-04-29T08:50:54+00:00"
},
{
"activity_id": 12,
"app": "systemtags",
"type": "systemtags",
"user": "admin",
"subject": "Added system tag tag1",
"subject_rich": [
"Added system tag {systemtag}",
{
"systemtag": {
"type": "systemtag",
"id": 1,
"name": "tag1",
"assignable": "1",
"visibility": "1"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "",
"objects": {
"776": ""
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/tag.svg",
"datetime": "2021-04-29T08:50:49+00:00"
},
{
"activity_id": 10,
"app": "files_sharing",
"type": "shared",
"user": "admin",
"subject": "Shared as public link",
"subject_rich": [
"Shared as public link",
{
"file": {
"type": "file",
"id": "776",
"name": "Test file - renamed.md",
"path": "Test file - renamed.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/Test file - renamed.md",
"objects": {
"776": "\/Test file - renamed.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/share.svg",
"datetime": "2021-04-29T08:49:55+00:00"
},
{
"activity_id": 9,
"app": "files",
"type": "file_changed",
"user": "admin",
"subject": "You moved Templates\/Test file - renamed.md to ",
"subject_rich": [
"You moved {oldfile} to {newfile}",
{
"newfile": {
"type": "file",
"id": "710",
"name": "",
"path": "",
"link": "http:\/\/localhost:8080\/index.php\/f\/710"
},
"oldfile": {
"type": "file",
"id": "776",
"name": "Test file - renamed.md",
"path": "Templates\/Test file - renamed.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/\/Test file - renamed.md",
"objects": {
"776": "\/\/Test file - renamed.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/",
"icon": "http:\/\/localhost:8080\/apps\/files\/img\/change.svg",
"datetime": "2021-04-29T08:49:44+00:00"
},
{
"activity_id": 8,
"app": "files",
"type": "file_changed",
"user": "admin",
"subject": "You renamed Templates\/Test file.md to Templates\/Test file - renamed.md",
"subject_rich": [
"You renamed {oldfile} to {newfile}",
{
"newfile": {
"type": "file",
"id": "776",
"name": "Test file - renamed.md",
"path": "Templates\/Test file - renamed.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
},
"oldfile": {
"type": "file",
"id": "776",
"name": "Test file.md",
"path": "Templates\/Test file.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/Templates\/Test file - renamed.md",
"objects": {
"776": "\/Templates\/Test file - renamed.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/Templates",
"icon": "http:\/\/localhost:8080\/apps\/files\/img\/change.svg",
"datetime": "2021-04-29T08:49:40+00:00"
},
{
"activity_id": 7,
"app": "files",
"type": "file_changed",
"user": "admin",
"subject": "You moved Documents\/Test file.md to Templates",
"subject_rich": [
"You moved {oldfile} to {newfile}",
{
"newfile": {
"type": "file",
"id": "754",
"name": "Templates",
"path": "Templates",
"link": "http:\/\/localhost:8080\/index.php\/f\/754"
},
"oldfile": {
"type": "file",
"id": "776",
"name": "Test file.md",
"path": "Documents\/Test file.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/Templates\/Test file.md",
"objects": {
"776": "\/Templates\/Test file.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/Templates",
"icon": "http:\/\/localhost:8080\/apps\/files\/img\/change.svg",
"datetime": "2021-04-29T08:49:28+00:00"
},
{
"activity_id": 6,
"app": "files",
"type": "file_changed",
"user": "admin",
"subject": "You moved Test file.md to Documents",
"subject_rich": [
"You moved {oldfile} to {newfile}",
{
"newfile": {
"type": "file",
"id": "753",
"name": "Documents",
"path": "Documents",
"link": "http:\/\/localhost:8080\/index.php\/f\/753"
},
"oldfile": {
"type": "file",
"id": "776",
"name": "Test file.md",
"path": "Test file.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/Documents\/Test file.md",
"objects": {
"776": "\/Documents\/Test file.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/Documents",
"icon": "http:\/\/localhost:8080\/apps\/files\/img\/change.svg",
"datetime": "2021-04-29T08:49:19+00:00"
},
{
"activity_id": 5,
"app": "files",
"type": "favorite",
"user": "admin",
"subject": "Added to favorites",
"subject_rich": [
"",
[]
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "Test file.md",
"objects": {
"776": "Test file.md"
},
"link": "",
"icon": "http:\/\/localhost:8080\/core\/img\/actions\/starred.svg",
"datetime": "2021-04-29T08:49:16+00:00"
},
{
"activity_id": 4,
"app": "files",
"type": "file_changed",
"user": "admin",
"subject": "You changed Test file.md",
"subject_rich": [
"You changed {file}",
{
"file": {
"type": "file",
"id": "776",
"name": "Test file.md",
"path": "Test file.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/Test file.md",
"objects": {
"776": "\/Test file.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/",
"icon": "http:\/\/localhost:8080\/apps\/files\/img\/change.svg",
"datetime": "2021-04-29T08:49:09+00:00"
},
{
"activity_id": 3,
"app": "files",
"type": "file_created",
"user": "admin",
"subject": "You created Test file.md",
"subject_rich": [
"You created {file}",
{
"file": {
"type": "file",
"id": "776",
"name": "Test file.md",
"path": "Test file.md",
"link": "http:\/\/localhost:8080\/index.php\/f\/776"
}
}
],
"message": "",
"message_rich": [
"",
[]
],
"object_type": "files",
"object_id": 776,
"object_name": "\/Test file.md",
"objects": {
"776": "\/Test file.md"
},
"link": "http:\/\/localhost:8080\/index.php\/apps\/files\/?dir=\/",
"icon": "http:\/\/localhost:8080\/apps\/files\/img\/add-color.svg",
"datetime": "2021-04-29T08:49:01+00:00"
}
]
}
}

Просмотреть файл

@ -0,0 +1,16 @@
const axios = jest.createMockFromModule('@nextcloud/axios')
const wsData = require('./activity_ws.json')
axios.get = async function(url) {
return new Promise((resolve, reject) => {
if (url === 'http://localhostundefined/ocs/v2.php/apps/activity/api/v2/activity/filter') {
resolve({ data: wsData })
} else {
// eslint-disable-next-line no-console
console.log(url)
}
})
}
export default axios

Просмотреть файл

@ -1,7 +1,3 @@
module.exports = {
plugins: [
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-proposal-class-properties',
],
presets: ['@babel/preset-env'],
}
const babelConfig = require('@nextcloud/babel-config')
module.exports = babelConfig

6
cypress.json Normal file
Просмотреть файл

@ -0,0 +1,6 @@
{
"baseUrl": "https://localhost:8081/index.php/",
"projectId": "hx9gqy",
"viewportWidth": 1280,
"viewportHeight": 720
}

1
cypress/.env Normal file
Просмотреть файл

@ -0,0 +1 @@
APP_SOURCE=/home/runner/work/activity/activity

5
cypress/.eslintrc.json Normal file
Просмотреть файл

@ -0,0 +1,5 @@
{
"extends": [
"plugin:cypress/recommended"
]
}

6
cypress/Dockerfile Normal file
Просмотреть файл

@ -0,0 +1,6 @@
FROM nextcloudci/server:latest
RUN mkdir /var/www/html/data
RUN chown -R www-data:www-data /var/www/html/data
ENTRYPOINT /usr/local/bin/initAndRun.sh

Просмотреть файл

@ -0,0 +1,14 @@
version: '3'
services:
nextcloud:
build:
context: .
restart: always
ports:
- 8081:80
environment:
CYPRESS_baseUrl:
APP_SOURCE:
volumes:
- ${APP_SOURCE}:/var/www/html/apps/activity

Просмотреть файл

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

Просмотреть файл

@ -0,0 +1,92 @@
/**
* @copyright Copyright (c) 2021 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { randHash } from '../utils'
const randUser = randHash()
describe('Open test.md in viewer', function() {
before(function() {
cy.nextcloudCreateUser(randUser, 'password')
cy.login(randUser, 'password')
cy.visit('/apps/files')
cy.wait(1000)
})
after(function() {
cy.logout()
})
it('Has creation activity', function() {
cy.showActivityTab('welcome.txt')
cy.get('.activity-entry').eq(0).should('contains.text', 'You created')
})
it('Has favorite activity', function() {
cy.addToFavorites('welcome.txt')
cy.showActivityTab('welcome.txt')
cy.get('.activity-entry').eq(0).should('contains.text', 'Added to favorites')
cy.removeFromFavorites('welcome.txt')
cy.showActivityTab('welcome.txt')
cy.get('.activity-entry').eq(0).should('contains.text', 'Removed from favorites')
})
it('Has share activity', function() {
cy.createPublicShare('welcome.txt')
cy.showActivityTab('welcome.txt')
cy.get('.activity-entry').eq(0).should('contains.text', 'Shared as public link')
})
it('Has rename activity', function() {
cy.renameFile('welcome.txt', 'new name')
cy.renameFile('new name.txt', 'welcome')
cy.showActivityTab('welcome.txt')
cy.get('.activity-entry').eq(0).should('contains.text', 'You renamed')
})
it('Has move activity', function() {
cy.createFolder('Test folder')
cy.moveFile('welcome.txt', 'Test folder')
cy.goToDir('Test folder')
cy.showActivityTab('welcome.txt')
cy.get('.activity-entry').eq(0).should('contains.text', 'You moved')
})
it('Has tag activity', function() {
cy.addTag('welcome.txt', 'my_tag')
cy.showActivityTab('welcome.txt')
cy.get('.activity-entry').eq(0).should('contains.text', 'Added system tag')
})
it('Has comment activity', function() {
cy.addComment('welcome.txt', 'A comment')
cy.showActivityTab('welcome.txt')
cy.get('.activity-entry').eq(0).should('contains.text', 'You commented')
})
})

22
cypress/plugins/index.js Normal file
Просмотреть файл

@ -0,0 +1,22 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

19
cypress/runLocal.sh Executable file
Просмотреть файл

@ -0,0 +1,19 @@
#!/bin/bash
export CYPRESS_baseUrl=http://localhost:8081/index.php
export APP_SOURCE=$PWD/..
function finish {
docker-compose down
}
trap finish EXIT
docker-compose up -d
npm install --no-save wait-on
$(npm bin)/wait-on -i 500 -t 240000 $CYPRESS_baseUrl || (cd cypress && docker-compose logs && exit 1)
docker-compose exec -T nextcloud bash /var/www/html/apps/activity/cypress/server.sh
(cd .. && $(npm bin)/cypress $@)

7
cypress/server.sh Normal file
Просмотреть файл

@ -0,0 +1,7 @@
#!/bin/bash
git clone https://github.com/nextcloud/activity /var/www/html/apps/activity
su www-data -c "
php occ config:system:set force_language --value en
php /var/www/html/occ app:enable activity
php /var/www/html/occ app:list
"

162
cypress/support/commands.js Normal file
Просмотреть файл

@ -0,0 +1,162 @@
/**
* @copyright Copyright (c) 2021 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command'
import axios from '@nextcloud/axios'
addMatchImageSnapshotCommand()
const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '')
Cypress.env('baseUrl', url)
Cypress.Commands.add('login', (user, password, route = '/apps/files') => {
cy.clearCookies()
Cypress.Cookies.defaults({
preserve: /^(oc|nc)/,
})
cy.visit(route)
cy.get('input[name=user]').type(user)
cy.get('input[name=password]').type(password)
cy.get('#submit-wrapper input[type=submit]').click()
cy.url().should('include', route)
})
Cypress.Commands.add('logout', () => {
Cypress.Cookies.defaults({
preserve: [],
})
cy.clearLocalStorage()
cy.clearCookies()
Cypress.Cookies.defaults({
preserve: /^(oc|nc)/,
})
})
Cypress.Commands.add('nextcloudCreateUser', (user, password) => {
cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/ocs/v1.php/cloud/users?format=json`,
form: true,
body: {
userid: user,
password,
},
auth: { user: 'admin', pass: 'admin' },
headers: {
'OCS-ApiRequest': 'true',
'Content-Type': 'application/x-www-form-urlencoded',
},
}).then(response => {
cy.log(`Created user ${user}`, response.status)
})
})
Cypress.Commands.add('createFolder', dirName => {
cy.get('#controls .actions > .button.new').click()
cy.get('#controls .actions .newFileMenu a[data-action="folder"]').click()
cy.get('#controls .actions .newFileMenu a[data-action="folder"] input[type="text"]').type(dirName)
cy.get('#controls .actions .newFileMenu a[data-action="folder"] input.icon-confirm').click()
cy.log('Created folder', dirName)
cy.wait(500)
})
Cypress.Commands.add('moveFile', (fileName, dirName) => {
cy.get(`#fileList tr[data-file="${fileName}"] .icon-more`).click()
cy.get(`#fileList tr[data-file="${fileName}"] .action-movecopy`).click()
cy.get(`.oc-dialog tr[data-entryname="${dirName}"]`).click()
cy.contains(`Move to ${dirName}`).click()
cy.wait(500)
})
Cypress.Commands.add('showSidebarForFile', fileName => {
cy.hideSidebar('welcome.txt')
cy.get('#fileList tr[data-file="welcome.txt"] .icon-more').click()
cy.contains('Details').click()
cy.get('#app-sidebar-vue').contains('Activity').click()
})
Cypress.Commands.add('hideSidebar', fileName => {
cy.get('body')
.then(($body) => {
if ($body.find('.app-sidebar__close').length !== 0) {
cy.get('.app-sidebar__close').click()
}
})
})
Cypress.Commands.add('showActivityTab', fileName => {
cy.showSidebarForFile()
cy.get('#app-sidebar-vue').contains('Activity').click()
})
Cypress.Commands.add('addToFavorites', fileName => {
cy.get(`#fileList tr[data-file="${fileName}"] .icon-more`).click()
cy.contains('Add to favorites').click()
})
Cypress.Commands.add('removeFromFavorites', fileName => {
cy.get(`#fileList tr[data-file="${fileName}"] .icon-more`).click()
cy.contains('Remove from favorites').click()
})
Cypress.Commands.add('createPublicShare', fileName => {
cy.get(`#fileList tr[data-file="${fileName}"] .icon-more`).click()
cy.contains('Details').click()
cy.get('#app-sidebar-vue').contains('Sharing').click()
cy.get('#app-sidebar-vue a#sharing').trigger('click')
cy.get('#app-sidebar-vue button.new-share-link').trigger('click')
cy.get('#app-sidebar-vue a.sharing-entry__copy')
})
Cypress.Commands.add('renameFile', (fileName, newName) => {
cy.get(`#fileList tr[data-file="${fileName}"] .icon-more`).click()
cy.get(`#fileList tr[data-file="${fileName}"] .action-rename`).click()
cy.get(`#fileList tr[data-file="${fileName}"] input.filename`).type(newName).parent().submit()
cy.wait(500)
})
Cypress.Commands.add('goToDir', (dirName) => {
cy.get(`#fileList tr[data-file="${dirName}"]`).click()
cy.wait(500)
})
Cypress.Commands.add('addTag', (fileName, tag) => {
cy.showSidebarForFile('welcome.txt')
cy.get('.app-sidebar-header__menu .action-item__menutoggle').click()
cy.get('.action-button__icon.icon-tag').click()
cy.get('.systemTagsInputField input').type('my_tag{enter}{esc}')
cy.wait(500)
})
Cypress.Commands.add('addComment', (fileName, comment) => {
cy.showSidebarForFile('welcome.txt')
cy.get('#app-sidebar-vue').contains('Comments').click()
cy.get('.comment__editor .rich-contenteditable__input').type(comment)
cy.get('input.comment__submit').click()
cy.wait(500)
})

20
cypress/support/index.js Normal file
Просмотреть файл

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

25
cypress/utils/index.js Normal file
Просмотреть файл

@ -0,0 +1,25 @@
/**
* @copyright Copyright (c) 2021 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
const randHash = () => Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10)
export default { randHash }

6407
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -24,7 +24,8 @@
"stylelint": "stylelint css/*.css css/*.scss src/**/*.scss src/**/*.vue",
"stylelint:fix": "stylelint css/*.css css/*.scss src/**/*.scss src/**/*.vue --fix",
"test": "NODE_ENV=test jest --passWithNoTests src/",
"test:coverage": "NODE_ENV=test jest --coverage src/"
"test:coverage": "NODE_ENV=test jest --coverage src/",
"test:update-snapshots": "NODE_ENV=test jest --updateSnapshot"
},
"engines": {
"node": ">=10.0.0"
@ -39,13 +40,33 @@
"json",
"vue"
],
"testEnvironment": "jest-environment-jsdom-sixteen",
"transform": {
".*\\.(vue)$": "vue-jest",
"^.+\\.js$": "babel-jest"
"^.+\\.js$": "babel-jest",
"^.+\\.vue$": "vue-jest"
},
"transformIgnorePatterns": [
"\\.pnp\\.[^\\/]+$",
"/node_modules/(?!(@juliushaertl/vue-richtext)/)"
],
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
],
"setupFilesAfterEnv": [
"./src/tests/setup.js"
],
"coverageDirectory": "./coverage/",
"collectCoverage": false,
"collectCoverageFrom": [
"<rootDir>/src/**/*.{js,vue}",
"!**/node_modules/**"
],
"coverageReporters": [
"json",
"text",
"html",
"lcov",
"clover"
]
},
"dependencies": {
@ -59,30 +80,31 @@
"@nextcloud/vue": "^3.9.0",
"vue": "^2.6.12"
},
"browserslist": [
"extends @nextcloud/browserslist-config"
],
"engines": {
"node": ">=10.0.0"
},
"devDependencies": {
"@babel/core": "^7.13.16",
"@babel/eslint-parser": "^7.13.14",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.13.15",
"@cypress/browserify-preprocessor": "^3.0.1",
"@nextcloud/babel-config": "^1.0.0-beta.1",
"@nextcloud/browserslist-config": "^2.1.0",
"@nextcloud/eslint-config": "^5.0.0",
"@nextcloud/eslint-plugin": "^2.0.0",
"@nextcloud/webpack-vue-config": "^4.0.3",
"@testing-library/vue": "^5.6.2",
"@vue/test-utils": "^1.1.4",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
"babel-loader": "^8.2.2",
"css-loader": "^4.3.0",
"cypress": "^7.2.0",
"cypress-image-snapshot": "^4.0.1",
"eslint": "^7.25.0",
"eslint-config-standard": "^16.0.2",
"eslint-import-resolver-webpack": "^0.13.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-cypress": "^2.11.3",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.3.1",
@ -90,6 +112,9 @@
"eslint-plugin-vue": "^7.9.0",
"eslint-webpack-plugin": "^2.5.4",
"file-loader": "^6.2.0",
"jest": "^26.6.3",
"jest-environment-jsdom-sixteen": "^2.0.0",
"jest-serializer-vue": "^2.0.2",
"node-polyfill-webpack-plugin": "^1.1.0",
"sass": "^1.32.11",
"sass-loader": "^10.0.5",
@ -99,6 +124,7 @@
"stylelint-scss": "^3.19.0",
"stylelint-webpack-plugin": "^2.1.1",
"url-loader": "^4.1.1",
"vue-jest": "^3.0.7",
"vue-loader": "^15.9.6",
"vue-template-compiler": "^2.6.12",
"webpack": "^5.36.0",

5
src/tests/.eslintrc.js Normal file
Просмотреть файл

@ -0,0 +1,5 @@
module.exports = {
env: {
jest: true,
},
}

148
src/tests/Activity.test.js Normal file
Просмотреть файл

@ -0,0 +1,148 @@
/**
* @copyright Copyright (c) 2021 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { render } from '@testing-library/vue'
import Vue from 'vue'
import Activity from '../components/Activity.vue'
import ActivityModel from '../models/ActivityModel'
const wsData = require('../../__mocks__/@nextcloud/activity_ws.json')
jest.useFakeTimers()
const currentDate = new Date('2021-05-10T12:00:00+00:00')
const realDateNow = Date.now
beforeAll(() => {
global.Date.now = jest.fn(() => currentDate.getTime())
})
afterAll(() => {
global.Date.now = realDateNow
})
test('Display relative date gets updated every minutes', async() => {
const { baseElement, getByText } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[1]) } })
expect(baseElement.textContent).toContain('You renamed Test file - renamed.md to Test file - renamed - looooooooong.md')
getByText('11 days ago')
const currentDatePlusOneDay = new Date('2021-05-11T12:00:00+00:00')
global.Date.now = jest.fn(() => currentDatePlusOneDay.getTime())
jest.advanceTimersByTime(60 * 1000)
await Vue.nextTick()
getByText('12 days ago')
global.Date.now = jest.fn(() => currentDate.getTime())
})
test('Display correct information for renames', async() => {
const { baseElement, getByText } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[1]) } })
expect(baseElement.textContent).toContain('You renamed Test file - renamed.md to Test file - renamed - looooooooong.md')
const originalFileNameElement = getByText('Test file - renamed.md')
expect(originalFileNameElement.nodeName).toBe('A')
const newFileNameElement = getByText('Test file - renamed - looooooooong.md')
expect(newFileNameElement.nodeName).toBe('A')
expect(baseElement.innerHTML).toMatchSnapshot()
})
test('Display correct information for comments', async() => {
const { baseElement } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[4]) } })
expect(baseElement.textContent).toContain('You commented')
expect(baseElement.textContent).toContain('A comment')
expect(baseElement.innerHTML).toMatchSnapshot()
})
test('Display correct information for favorites', async() => {
const { baseElement } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[5]) } })
expect(baseElement.textContent).toContain('Added to favorites')
expect(baseElement.innerHTML).toMatchSnapshot()
})
test('Display correct information for unfavorites', async() => {
const { baseElement } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[6]) } })
expect(baseElement.textContent).toContain('Removed from favorites')
expect(baseElement.innerHTML).toMatchSnapshot()
})
test('Display correct information for changes', async() => {
const { baseElement, getByText } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[7]) } })
expect(baseElement.textContent).toContain('You changed Test file - renamed.md')
const fileNameElement = getByText('Test file - renamed.md')
expect(fileNameElement.nodeName).toBe('A')
expect(baseElement.innerHTML).toMatchSnapshot()
})
test('Display correct information for tags', async() => {
const { baseElement } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[9]) } })
expect(baseElement.textContent).toContain('Added system tag tag1')
expect(baseElement.innerHTML).toMatchSnapshot()
})
test('Display correct information for shares', async() => {
const { baseElement } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[10]) } })
expect(baseElement.textContent).toContain('Shared as public link')
expect(baseElement.innerHTML).toMatchSnapshot()
})
test('Display correct information for moves', async() => {
const { baseElement, getByText } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[14]) } })
expect(baseElement.textContent).toContain('You moved Test file.md to Documents')
const fileNameElement = getByText('Test file.md')
expect(fileNameElement.nodeName).toBe('A')
const destinationElement = getByText('Documents')
expect(destinationElement.nodeName).toBe('A')
expect(baseElement.innerHTML).toMatchSnapshot()
})
test('Display correct information for creations', async() => {
const { baseElement, getByText } = render(Activity, { props: { activity: new ActivityModel(wsData.ocs.data[17]) } })
expect(baseElement.textContent).toContain('You created Test file.md')
const fileNameElement = getByText('Test file.md')
expect(fileNameElement.nodeName).toBe('A')
expect(baseElement.innerHTML).toMatchSnapshot()
})

Просмотреть файл

@ -0,0 +1,34 @@
/**
* @copyright Copyright (c) 2021 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { mount } from '@vue/test-utils'
import ActivityTab from '../views/ActivityTab.vue'
test('Create ActivityTab', async() => {
const wrapper = mount(ActivityTab, {})
expect(wrapper.vm.$data.activities.length).toBe(0)
await wrapper.vm.update({ id: 'test' })
expect(wrapper.vm.$data.activities.length).toBe(18)
})

51
src/tests/OC.js Normal file
Просмотреть файл

@ -0,0 +1,51 @@
/**
* @copyright Copyright (c) 2021 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
export default {
L10N: {
translate() {
return ''
},
},
getLanguage() {
return 'en-GB'
},
getLocale() {
return 'en_GB'
},
isUserAdmin() {
return true
},
Util: {
naturalSortCompare(a, b) {
return 0
},
},
config: {
modRewriteWorking: true,
},
}

31
src/tests/setup.js Normal file
Просмотреть файл

@ -0,0 +1,31 @@
/**
* @copyright Copyright (c) 2021 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import OC from './OC.js'
import Vue from 'vue'
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
global.OC = OC
Vue.prototype.t = t
Vue.prototype.n = n

Просмотреть файл

@ -74,7 +74,7 @@ export default {
async update(fileInfo) {
this.fileInfo = fileInfo
this.resetState()
this.getActivities()
await this.getActivities()
},
/**
* Get the existing activities