npx在线调用

npx 指令从npm5.2就内置了,可以在线调用npm包而不用下载到本地再执行

ie: cowsay 指令

1
2
3
4
5
6
7
8
9
10
➜  ~ npx cowsay owow
______
< owow >
------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
➜ ~

可以直接编译&运行ts文件

1
npx ts-node script.ts

可以执行 create-react-app 脚本

1
npx create-react-app .

也可以调用自己写的GitHub gist代码片段

1
2
3
4
5
➜  my-project git:(main) npx https://gist.github.com/miloweimo/491623a136c0ceed0371c10ae95c86a0
Need to install the following packages:
gist:491623a136c0ceed0371c10ae95c86a0
Ok to proceed? (y)
helllllloooooo~~

参考

我写的hellojs https://gist.github.com/miloweimo/491623a136c0ceed0371c10ae95c86a0

别人写的hellojs https://gist.github.com/Tynael/0861d31ea17796c9a5b4a0162eb3c1e8

别人写的readme https://gist.github.com/CarsonSlovoka/ad04ee083bd2dde825060160546b8059

免输密码直接scp传文件的研究

❌ yes指令

1
(yes ${PWD} | head -2 && yes y | head -1) | scp test xx@yy:zz

实测不行

❌ scp -S参数

没有这个写法

✅添加公钥到服务器

可以直接scp

✅sshpass输密码

可以但是部分系统不支持

前端项目添加 打包脚本 部署脚本 生成改动日志脚本

打包脚本

package.json 添加

1
2
3
// ..
"zip": "zip -r dist-$(git rev-parse --abbrev-ref HEAD)-$npm_package_name-$npm_package_version-$(date +'%Y_%m_%d').zip dist/ && open .",
"bz": "npm run build && npm run zip"

然后运行 npm run bz 就能直接打开打包好的zip包目录

阅读更多

cypress测试框架基础用法

E2E库 Cypress

端到端End to End (E2E)测试,将系统作为一个整体的测试方法

准备工作

首先有一个前端项目的打包文件,可以启动的后端服务,来做自动化e2e测试

安装配置

1
npm install --save-dev cypress # 将 Cypress 安装到前端 ,作为开发依赖项

配置package.json 添加脚本 cypress:opentest:e2e

1
2
3
4
5
6
7
8
9
10
11
12
13
{
// ..
"scripts": {
"start": "webpack-dev-server --open --mode development",
"start-prod": "node app.js",
"test": "jest",
"eslint": "eslint './**/*.{js,jsx}'",
"cypress:open": "cypress open",
"test:e2e": "cypress run",
"build": "webpack --mode production"
},
// ..
}

后端服务也可以添加启动指令 "start-prod": "node app.js"

app.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
const express = require('express')
const app = express()

// get the port from env variable
const PORT = process.env.PORT || 5001

app.use(express.static('dist'))

app.listen(PORT, () => {
// eslint-disable-next-line
console.log(`server started on port ${PORT}`, `http://localhost:${PORT}`)
})

ps: 对于 const express = require('express')的eslint报错,可以在.eslintrc.js中添加配置

1
2
3
4
5
6

'env': {
// ..
'node': true,
'commonjs': true,
},

.gitignore 也可把视频添加忽略 cypress/videos

首次启动

首次启动cypress 项目根目录会多一个 cypress 文件夹和一个配置文件 cypress.config.js

1
npm run cypress:open

cypress.config.js:

1
2
3
4
5
6
7
8
9
10
11
12
// cypress.config.js
const { defineConfig } = require('cypress')

module.exports = defineConfig({
e2e: {
// eslint-disable-next-line
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
})

目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
➜  my-proj git:(main) ✗ tree -L 2 
.
├── README.md
├── app.js
├── cypress
│ ├── e2e
│ ├── fixtures
│ ├── screenshots
│ └── support
├── cypress.config.js
├── dist
│ ├── bundle.js
│ ├── bundle.js.LICENSE.txt
│ └── index.html
# ..

第一次Cypress会在 integration/examples 目录中创建测试示例 可以删了examples文件夹

cy 导致的 eslint 风格报错

报错大概这样

1
2
3
4
5
6
7
8
9
10
11
12
13
 *  正在执行任务: npm run eslint 


> my-proj@1.0.0 eslint
> eslint './**/*.{js,jsx}'

Warning: React version not specified in eslint-plugin-react settings. See https://github.com/jsx-eslint/eslint-plugin-react#configuration .

/Users/weimo/mine/code/my-proj/cypress/e2e/app.cy.js
3:5 error 'cy' is not defined no-undef
4:5 error 'cy' is not defined no-undef
5:5 error 'cy' is not defined no-undef
# ..

我们可以通过安装eslint-plugin-cypress作为开发依赖项来摆脱这个报错

1
npm install eslint-plugin-cypress --save-dev

改变 .eslintrc.js中的配置 (vscode安装了eslint拓展需要修改setting.json)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = {
"env": {
"browser": true,
"es6": true,
"jest/globals": true,
"cypress/globals": true
},
"extends": [
// ...
],
"parserOptions": {
// ...
},
"plugins": [
"react", "jest", "cypress"
],
"rules": {
// ...
}
}

编写运行测试

添加文件 cypress/e2e/app.cy.js:

1
2
3
4
5
6
7
describe('Pokedex', function() {
it('front page can be opened 主页应该能打开', function() {
cy.visit('http://localhost:5001')
cy.contains('ivysaur') // 代码是全小写的,页面由css控制显示为首字大写,所以这里小写
cy.contains('Pokémon and Pokémon character names are trademarks of Nintendo.')
})
})

启动测试

启动服务 运行目前的测试是测试5001端口

可以运行 npm run cypress:open 后使用交互界面看结果:

Cypress demo

也可以运行 npm run test:e2e 后在控制台看到结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
正在执行任务: npm run test:e2e 


> my-proj@1.0.0 test:e2e
> cypress run


DevTools listening on ws://127.0.0.1:55305/devtools/browser/25c805c0-5b4b-4250-9c9e-6cc43f8184a8
2024-06-20 17:58:23.038 Cypress[4588:4056456] WARNING: Secure coding is not enabled for restorable state! Enable secure coding by implementing NSApplicationDelegate.applicationSupportsSecureRestorableState: and returning YES.
Couldn't find tsconfig.json. tsconfig-paths will be skipped

====================================================================================================

(Run Starting)

┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Cypress: 13.12.0 │
│ Browser: Electron 118 (headless) │
│ Node Version: v16.20.2 (/Users/weimo/.nvm/versions/node/v16.20.2/bin/node) │
│ Specs: 1 found (app.cy.js) │
│ Searched: cypress/e2e/**/*.cy.{js,jsx,ts,tsx} │
└────────────────────────────────────────────────────────────────────────────────────────────────┘


────────────────────────────────────────────────────────────────────────────────────────────────────

Running: app.cy.js (1 of 1)


Pokedex
1) front page can be opened 主页应该能打开

详情页测试
✓ 主页有charmander小火龙入口 (273ms)
✓ 点击小火龙详情页应该显示详情 (1012ms)
✓ 进入小火龙详情页后,能够进入前一个详情页 (1514ms)
✓ 进入小火龙详情页后,能够进入下一个详情页 (912ms)
✓ 进入小火龙详情页后,能够返回主页 (855ms)
# ..
(Screenshots)

- /Users/weimo/mine/code/my-proj/cypress/screenshots/app.cy.js/Pok (1280x720)
edex -- front page can be opened 主页应该能打开 (failed).png


====================================================================================================

(Run Finished)


Spec Tests Passing Failing Pending Skipped
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ✖ app.cy.js 01:05 6 5 1 - - │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
✖ 1 of 1 failed (100%) 01:05 6 5 1 - -


* 终端进程“/bin/zsh '-i', '-c', 'npm run test:e2e'”已终止,退出代码: 1。
* 终端将被任务重用,按任意键关闭。

一个测试示例文件

文档 https://docs.cypress.io/

查找内容 cy.contains() cy.get() cy.find() cy.should() 点击按钮 检测数据变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
describe('blog app',function () {

beforeEach(function () {
cy.request('POST','http://localhost:3003/api/testing/reset')
const user = {
name: 'DASB',
username: 'sb',
password: '123456'
}
cy.request('POST','http://localhost:3003/api/users', user)
cy.visit('http://localhost:3000')
})


it('can open site 可以打开网页',function () {
cy.visit('http://localhost:3000')
cy.contains('blogs')
})

it('and its have login form 显示登录表单',function () {
cy.contains('username')
cy.contains('password')
})

describe('login 登录测试',function () {

it('can not log in with incorrect credentials 错误信息不可以登录',function () {
cy.get('#username-login').type('dasb')
cy.get('#password-login').type('dasb')
cy.get('#login-button').click()

cy.contains('error')
})

it('can log in with correct info 正确信息可以登录',function () {
cy.get('#username-login').type('sb')
cy.get('#password-login').type('123456')
cy.get('#login-button').click()

cy.contains('success')
})

})

describe('When logged in', function() {
beforeEach(function () {
cy.login({ username: 'sb', password: '123456' })
})

it('A blog can be created', function() {
cy.contains('create a new blog').click()
cy.get('#title').type('标题')
cy.get('#author').type('作者')
cy.get('#url').type('链接')
cy.get('#likes').type('666')
cy.contains('submit').click()
cy.contains('标题 作者')
})

it('open show details and click like!', function () {

cy.createBlog({ title:'Test', author:'T est',url:'hppp:%%test@tset.com',likes:999 })

cy.contains('Test').find('button:first').as('theShowDetailButton') // 找到show detail按钮
// 然后我们点击按钮,检查上面的文本是否改变
cy.get('@theShowDetailButton').click()
cy.get('@theShowDetailButton').should('contain', 'hide detail')

cy.get('#add-likes-button').as('theLikeButton') // 找到show detail按钮
cy.contains(999)
cy.get('@theLikeButton').click()
cy.contains(1000)

})


it('blog can be deleted',function () {

cy.createBlog({ title:'this', author:'will',url:'remove',likes:0 })

cy.get('#show-detail-button').as('theShowDetailButton')
cy.get('@theShowDetailButton').click()
cy.contains('this')
cy.contains('will')
cy.contains('remove')

cy.get('#delete-button').click()
cy.contains('delete blog')
cy.should('not.contain','this')
cy.should('not.contain','will')
cy.should('not.contain','remove')

})

describe('the order is correct order by likes',function () {

beforeEach(function () {

cy.createBlog({ title:'first', author:'hehe',url:'haha',likes:0 })
cy.createBlog({ title:'second', author:'hehe',url:'xxxx',likes:666 })
cy.createBlog({ title:'third', author:'hehe',url:'xxxx',likes:888 })
cy.createBlog({ title:'fourth', author:'hehe',url:'xxxx',likes:888 })
cy.createBlog({ title:'fifth', author:'hehe',url:'xxxx',likes:111 })
cy.createBlog({ title:'sixth', author:'will',url:'remove',likes:1001 })
})

it('have six blogs in correct order',function () {

// open all details
cy.get('#blog-list div').find('button:first').click({ multiple: true })

// blogList should in correct order
cy.get('#blog-list div')
.first().should('contain','sixth').should('contain',1001)
.next().should('contain','third').should('contain',888)
.next().should('contain','fourth').should('contain',888)
.next().should('contain','second').should('contain',666)
.next().should('contain','fifth').should('contain',111)
.next().should('contain','first').should('contain',0)

})

it('click fourth blog like! button, then the order change',function () {
// open all details
cy.get('#blog-list div').find('button:first').click({ multiple: true })

cy.get('#blog-list div')
.first()
.next()
.next().should('contain','fourth').should('contain',888).find('#add-likes-button').click()

cy.get('#blog-list div')
.first()
.next()
.next().should('contain','fourth').should('contain',889)
})

// describe('click like on fourth blog and check order',function () {

// beforeEach('click like',function () {

// cy.get('#blog-list div').find('button:first').click({ multiple: true })

// cy.get('#blog-list div')
// .first()
// .next()
// .next().should('contain','fourth').should('contain',888).find('#add-likes-button').click()
// })

// it('the order in correct',function () {
// cy.get('#blog-list div')
// .first()
// .next().should('contain','fourth').should('contain',889)

// })
// })

})
})
})

:src动态导入图片路径

对于webpack

1
const img = require(`./img/${name}.png`)
1
<img :src="img" />

或者直接在html中使用

1
2
<img :src="require(`./img/${name}.png`)" />
<img :src="require(`@/img/${name}.png`)" />

对于vite

1
2
// ..
activeIcon: new URL('@/assets/icon/intelligent-contro.png', import.meta.url).href,
1
2
3
4
5
<img
:src="item.activeIcon"
height="40"
alt=""
>

3-2-1 备份方案

The 3-2-1 backup strategy simply states that you should have 3 copies of your data (your production data and 2 backup copies) on two different media (disk and tape) with one copy off-site for disaster recovery

3-2-1的备份策略只是指出,您应该在两个不同的媒体(磁盘和磁带)上拥有3份数据副本(您的生产数据和2份备份副本),其中一份副本副本以供灾难恢复

Focus

开始专注🧘

不要做🙅

  • 避免过度疲劳
  • ADHD药物不要乱吃
  • 不要同时做多件事

专注练习

创造适宜环境限制干扰

  • 聚焦当下「过去和未来都不重要,唯一重要的时刻就是现在」远大的最终目标会造成心理压力,但是想这它不会让手上的小任务有什么帮助
  • 把手机放在看不到的地方,不去玩它——承认手机不好玩。why?手机作为奶头乐,要的就是让你沉迷,和烟酒没什么区别,刷手机刷的你脑子的多巴胺
  • 没必要特别关注社交媒体 被@、点赞完全是干扰
  • 赶走无关人员 避免来自家人、朋友、同事、同学的干扰
  • 使用手表的整点报时/震动功能,让你清楚了解时间流逝
  • 仪式感 开始之前,整理桌面,拿离手机
  • 降噪耳塞 (?游戏背景音乐可以专注
  • 过度摄入碳水会导致晕碳 中间可以使用榛子、杏仁等坚果来保持体力

制定计划和实施

  • 提前规划 避免在番茄钟的时间再规划
  • 任务更细化 平滑过渡番茄钟(每25mins休息5mins 这样就是半小时一段,便于记录一天中在干什么
  • 去除机心 上来就干,干完完事。避免方法论干扰。不要想的那种方法做这个事怎么有效率、怎么好
  • 不要做fake work 也没必要事事专注,做重要的事「现在最危险的陷阱是通过模仿更高尚的类型来绕过我们对自我放纵的警报的新行为」
  • 避免分心的灵感 没必要为了一点不成熟的想法打断心流,直接丢弃or速记下灵感
  • 参与感 提前预习、语音互动、眼神互动

专注力训练

  • 练习下棋,围棋、国际象棋、中国象棋练习专注的感觉
  • 从1开始螺旋写到97,中间分心就马上写^记下
  • 可以玩一下Super Hexagon,来测试你的专注 (类似网页游戏 https://tic80.com/play?cart=311

休息

  • Mind Sweep 把大脑积攒的所有想法统统倒出来,写下来
  • 冥想5mins
  • 保持锻炼🏋️ 做有氧 起来走走放空脑子
  • 充足睡眠

参考

为什么我无法专注:了解 ADHD

认真聊聊ADHD:注意力、肠胃失调、自我认知和「时髦病」

分心不是你的错——成人 ADHD 问诊指南

As someone with ADHD, the reliable hourly beep has really helped me stay on schedule, like a friendly tap on the shoulder. — @neeblerxd

《意志力》[美] 罗伊·鲍迈斯特

如何保持长时间专注?

庄周梦蝶

昔者庄周梦为胡蝶,栩栩然胡蝶也,自喻适志与!不知周也。俄然觉,则蘧蘧然周也。不知周之梦为胡蝶与,胡蝶之梦为周与?周与胡蝶,则必有分矣。此之谓物化。

以前庄子做梦变成蝴蝶,完全是一只欣然生动的蝴蝶,十分快活适意,全然不知道自己是庄周了。一会儿醒来,才惊讶自己原来是庄周。真不了解到底是庄周做梦变成蝴蝶呢,还是蝴蝶做梦变成了庄周呢?庄周与蝴蝶一定有分别。这就是所说的物化,也就是变化同为一体,不分彼此,消除物我差别的境界。

《庄子·齐物论》 - 中國哲學書電子化計劃

庄周梦蝶 - Wikiwand

蝶梦(蝶梦《庄子·齐物论》)_百度百科

子非鱼

庄子与惠子游于濠梁之上。庄子曰:“儵鱼出游从容,是鱼乐也。”惠子曰:“子非鱼,安知鱼之乐?”庄子曰:“子非我,安知我不知鱼之乐?”惠子曰:“我非子,固不知子矣;子固非鱼也,子之不知鱼之乐全矣。”庄子曰:“请循其本。子曰‘汝安知鱼乐’云者,既已知吾知之而问我,我知之濠上也。”

庄子和惠子一起在濠水的桥上游玩。庄子说:“鲦鱼在河水中游得多么悠闲自得,这是鱼的快乐啊。”惠子说:“你又不是鱼,哪里知道鱼是快乐的呢?”庄子说:“你又不是我,怎么知道我不知道鱼儿是快乐的呢?惠子说:“我不是你,固然就不知道你(的想法);你本来就不是鱼,你不知道鱼的快乐,这是可以完全确定的。”庄子说:“请你回归最开始的设定,你说:‘你哪里知道鱼快乐’这句话,就说明你很清楚我知道,所以才来问我是从哪里知道的。现在我告诉你,我是在濠水的桥上知道的。”

参考

《庄子·秋水》 - 中國哲學書電子化計劃

濠梁之辯 - Wikiwand

濠梁之辩_百度百科