refactor: 确立独立子工程架构 (backend, admin, mpuniapp) 并同步更新 AGENTS.md 规范
这个提交包含在:
@@ -0,0 +1,241 @@
|
||||
const platformInfo = process.env.uniTestPlatformInfo.toLocaleLowerCase()
|
||||
const isAndroid = platformInfo.startsWith('android')
|
||||
const isIos = platformInfo.startsWith('ios')
|
||||
const isHarmony = platformInfo.startsWith('harmony')
|
||||
const isApp = isAndroid || isIos || isHarmony
|
||||
const isWeb = platformInfo.startsWith('web')
|
||||
const isMP = platformInfo.startsWith('mp')
|
||||
const isAppWebView = process.env.UNI_AUTOMATOR_APP_WEBVIEW == 'true'
|
||||
|
||||
const PAGE_PATH = '/pages/API/action-sheet/action-sheet'
|
||||
|
||||
describe('showActionSheet', () => {
|
||||
if (isMP) {
|
||||
it('skip', () => {
|
||||
expect(1).toBe(1)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
let screenShotOptions = { fullPage: true };
|
||||
let page;
|
||||
let topSafeArea = 0
|
||||
|
||||
// 测试辅助函数
|
||||
async function setPageData(newData) {
|
||||
return await page.setData({ data: newData });
|
||||
}
|
||||
|
||||
async function showActionSheet(page) {
|
||||
const btn = await page.$('#btn-action-sheet-show')
|
||||
await btn.tap()
|
||||
await page.waitFor(1000);
|
||||
}
|
||||
|
||||
async function screenshot(fileName) {
|
||||
const image = isWeb ? await program.screenshot(screenShotOptions) : await program.device.screenshot(screenShotOptions);
|
||||
const options = fileName ? {
|
||||
customSnapshotIdentifier() {
|
||||
return fileName
|
||||
}
|
||||
} : {}
|
||||
if (!isAppWebView) {
|
||||
expect(image).toMatchImageSnapshot({ ...options,
|
||||
failureThresholdType: 'percent',
|
||||
failureThreshold: 0.002,
|
||||
});
|
||||
}
|
||||
expect(image).toSaveImageSnapshot(options);
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const windowInfo = await program.callUniMethod('getWindowInfo');
|
||||
topSafeArea = windowInfo.safeAreaInsets.top;
|
||||
if (isAppWebView) {
|
||||
if (isIos) {
|
||||
topSafeArea = 59
|
||||
if (platformInfo.includes('26')) {
|
||||
topSafeArea = 62
|
||||
}
|
||||
} else if (isAndroid) {
|
||||
topSafeArea = 24
|
||||
windowInfo.safeArea.bottom = 867
|
||||
if (platformInfo.startsWith('android 5')) {
|
||||
topSafeArea = 25
|
||||
}if (platformInfo.startsWith('android 6')) {
|
||||
windowInfo.safeArea.bottom = 592
|
||||
}if (platformInfo.startsWith('android 8')) {
|
||||
windowInfo.safeArea.bottom = 534
|
||||
} else if (platformInfo.startsWith('android 11')) {
|
||||
topSafeArea = 52
|
||||
} else if (platformInfo.startsWith('android 12')) {
|
||||
topSafeArea = 24
|
||||
windowInfo.safeArea.bottom = 716
|
||||
} else if (platformInfo.startsWith('android 13') || platformInfo.startsWith('android 15')) {
|
||||
topSafeArea = 49
|
||||
windowInfo.safeArea.bottom = 891
|
||||
} else if (platformInfo.startsWith('android 14')) {
|
||||
windowInfo.safeArea.bottom = 891
|
||||
}
|
||||
} else if (isHarmony) {
|
||||
topSafeArea = 39
|
||||
if (platformInfo.includes('nova_12')) {
|
||||
topSafeArea = 35
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page = await program.reLaunch('/pages/tabBar/API');
|
||||
await page.waitFor('view');
|
||||
|
||||
page = await program.navigateTo(PAGE_PATH)
|
||||
await page.waitFor('view');
|
||||
if (isApp) {
|
||||
if((isAndroid || isIos) && !isAppWebView){
|
||||
await page.callMethod('setThemeAuto')
|
||||
}
|
||||
const top = topSafeArea + 44
|
||||
// actionSheet overlays the page window and can extend below its content area.
|
||||
const bottom = windowInfo.safeArea.bottom
|
||||
const left = windowInfo.safeArea.left
|
||||
const right = windowInfo.safeArea.right - 10
|
||||
screenShotOptions = {
|
||||
deviceShot: true,
|
||||
area: {
|
||||
x: left,
|
||||
y: top,
|
||||
width: right - left,
|
||||
height: bottom - top
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("onload showActionSheet", async () => {
|
||||
await page.waitFor(isWeb ? 3000 : 1000);
|
||||
await screenshot();
|
||||
// 非交互关闭应触发 fail 回调
|
||||
if (!isMP) {
|
||||
const originLifeCycleNum = await page.callMethod('getLifeCycleNum');
|
||||
await program.navigateBack();
|
||||
await page.waitFor(1000);
|
||||
page = await program.navigateTo(PAGE_PATH)
|
||||
const newLifeCycleNum = await page.callMethod('getLifeCycleNum');
|
||||
expect(newLifeCycleNum).toBe(originLifeCycleNum + 2);
|
||||
}
|
||||
})
|
||||
|
||||
it("有标题", async () => {
|
||||
await setPageData({
|
||||
showErrorToast:false,
|
||||
current: 0,
|
||||
})
|
||||
await showActionSheet(page);
|
||||
await screenshot();
|
||||
})
|
||||
|
||||
it("有标题 长内容", async () => {
|
||||
await setPageData({
|
||||
itemContentLarge:true,
|
||||
})
|
||||
await showActionSheet(page);
|
||||
await screenshot();
|
||||
})
|
||||
|
||||
it("有标题 超过6个item", async () => {
|
||||
await setPageData({
|
||||
itemContentLarge:false,
|
||||
itemNumLargeSelect:true,
|
||||
})
|
||||
await showActionSheet(page);
|
||||
await screenshot();
|
||||
})
|
||||
|
||||
it("有标题 长内容 自定义 itemColor", async () => {
|
||||
await setPageData({
|
||||
itemContentLarge: true,
|
||||
itemNumLargeSelect: false,
|
||||
itemColorCustom: true,
|
||||
})
|
||||
await showActionSheet(page);
|
||||
await screenshot();
|
||||
})
|
||||
|
||||
it("无标题", async () => {
|
||||
await setPageData({
|
||||
current: 1,
|
||||
itemContentLarge:false,
|
||||
itemColorCustom:false,
|
||||
})
|
||||
await showActionSheet(page);
|
||||
await screenshot();
|
||||
})
|
||||
|
||||
it("长标题", async () => {
|
||||
await setPageData({
|
||||
current: 2,
|
||||
})
|
||||
await showActionSheet(page);
|
||||
await screenshot();
|
||||
})
|
||||
if (!isMP) {
|
||||
it("custom titleColor cancelText cancelColor backgroundColor", async () => {
|
||||
await setPageData({
|
||||
titleColorCustom: true,
|
||||
cancelTextCustom: true,
|
||||
cancelColorCustom: true,
|
||||
backgroundColorCustom: true,
|
||||
})
|
||||
await showActionSheet(page);
|
||||
await page.waitFor(1000)
|
||||
await screenshot();
|
||||
})
|
||||
}
|
||||
it("showActionSheet 并在回调中再次 showActionSheet", async () => {
|
||||
await page.callMethod('showActionSheetAndShowAgainInCallback')
|
||||
await page.waitFor(1000);
|
||||
await screenshot('showActionSheetAndShowAgainInCallback1');
|
||||
if (isApp) {
|
||||
await program.device.tap(200, 700)
|
||||
} else if (isWeb) {
|
||||
await page.callMethod('closeWebActionSheet')
|
||||
}
|
||||
await page.waitFor(1000);
|
||||
await screenshot('showActionSheetAndShowAgainInCallback2');
|
||||
})
|
||||
if (!isMP) {
|
||||
it("hideActionSheet", async () => {
|
||||
await page.callMethod('hideActionSheet')
|
||||
await page.waitFor(1000);
|
||||
|
||||
await screenshot();
|
||||
})
|
||||
}
|
||||
// 针对 https://issues.dcloud.net.cn/pages/issues/detail?id=19068 的补充测试,故仅测试 Android 一台设备
|
||||
if (platformInfo.startsWith('android 13')) {
|
||||
it('navigateBack in action-sheet success callback', async () => {
|
||||
const originLifeCycleNum = await page.callMethod('getLifeCycleNum');
|
||||
await page.callMethod('showActionSheetAndNavigateBackInSuccessCallback');
|
||||
await page.waitFor(1000);
|
||||
await program.device.tap(100, 700 + topSafeArea);
|
||||
// success callback + 1
|
||||
// 等待 back 完成
|
||||
await page.waitFor(1000);
|
||||
page = await program.navigateTo(PAGE_PATH)
|
||||
// 等待页面跳转完成
|
||||
await page.waitFor('view');
|
||||
const newLifeCycleNum = await page.callMethod('getLifeCycleNum');
|
||||
expect(newLifeCycleNum).toBe(originLifeCycleNum + 1);
|
||||
});
|
||||
}
|
||||
afterAll(async () => {
|
||||
if (!isMP) {
|
||||
await page.callMethod('hideActionSheet')
|
||||
await page.waitFor(1000);
|
||||
}
|
||||
await page.callMethod('setLifeCycleNumFunc', 1100);
|
||||
if(isApp && !isAppWebView){
|
||||
await page.callMethod('resetTheme')
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,301 @@
|
||||
<template>
|
||||
<!-- #ifdef APP && !VUE3-VAPOR -->
|
||||
<scroll-view style="flex: 1;">
|
||||
<!-- #endif -->
|
||||
<view>
|
||||
<page-head :title="data.title"></page-head>
|
||||
<page-intro content="本页演示 uni.showActionSheet:通过单选切换列表项、开关控制 titleColor/itemColor、超长与空文本 item、cancelText/cancelColor/backgroundColor 等;点击按钮弹出 actionSheet,可查看回调结果。"></page-intro>
|
||||
<view class="uni-list">
|
||||
<radio-group @change="radioChange">
|
||||
<radio class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in data.items" :key="item.value"
|
||||
:class="index < data.items.length - 1 ? 'uni-list-cell-line': ''" :value="item.value" :checked="index === data.current">
|
||||
{{item.name}}
|
||||
</radio>
|
||||
</radio-group>
|
||||
</view>
|
||||
<view class="uni-list">
|
||||
<view class="uni-list-cell uni-list-cell-pd">
|
||||
<view class="uni-list-cell-db">自定义 titleColor</view>
|
||||
<switch :checked="data.titleColorCustom" @change="titleColorChange" />
|
||||
</view>
|
||||
<view class="uni-list-cell uni-list-cell-pd">
|
||||
<view class="uni-list-cell-db">自定义 itemColor</view>
|
||||
<switch :checked="data.itemColorCustom" @change="itemColorChange" />
|
||||
</view>
|
||||
<view class="uni-list-cell uni-list-cell-pd">
|
||||
<view class="uni-list-cell-db">超长文本和空文本 item</view>
|
||||
<switch :checked="data.itemContentLarge" @change="itemContentLargeChange" />
|
||||
</view>
|
||||
<!-- #ifndef MP -->
|
||||
<view class="uni-list-cell uni-list-cell-pd">
|
||||
<view class="uni-list-cell-db">超过6个 item</view>
|
||||
<switch :checked="data.itemNumLargeSelect" @change="itemNumLargeChange" />
|
||||
</view>
|
||||
<view class="uni-list-cell uni-list-cell-pd">
|
||||
<view class="uni-list-cell-db">自定义 cancelText</view>
|
||||
<switch :checked="data.cancelTextCustom" @change="cancelTextChange" />
|
||||
</view>
|
||||
<view class="uni-list-cell uni-list-cell-pd">
|
||||
<view class="uni-list-cell-db">自定义 cancelColor</view>
|
||||
<switch :checked="data.cancelColorCustom" @change="cancelColorChange" />
|
||||
</view>
|
||||
<view class="uni-list-cell uni-list-cell-pd">
|
||||
<view class="uni-list-cell-db">自定义 backgroundColor</view>
|
||||
<switch :checked="data.backgroundColorCustom" @change="backgroundColorChange" />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<view class="uni-padding-wrap">
|
||||
<view class="uni-btn-v">
|
||||
<button class="uni-btn-v" type="default" @tap="showActionSheet" id="btn-action-sheet-show">弹出actionSheet</button>
|
||||
<button class="uni-btn-v uni-btn" type="default" @tap="showActionSheetAndShowAgainInCallback" id="btn-action-sheet-show">showActionSheet 并在回调中再次 showActionSheet</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #ifdef APP && !VUE3-VAPOR -->
|
||||
</scroll-view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<script setup lang="uts">
|
||||
import { state, setLifeCycleNum } from '@/store/index.uts'
|
||||
|
||||
type ItemType = {
|
||||
value: string,
|
||||
name: string,
|
||||
}
|
||||
|
||||
type DataType = {
|
||||
title: string;
|
||||
titleColorCustom: boolean;
|
||||
itemColorCustom: boolean;
|
||||
itemContentLarge: boolean;
|
||||
itemNumLargeSelect: boolean;
|
||||
cancelTextCustom: boolean;
|
||||
cancelColorCustom: boolean;
|
||||
backgroundColorCustom: boolean;
|
||||
showErrorToast: boolean;
|
||||
items: ItemType[];
|
||||
current: number;
|
||||
originTheme: string | null;
|
||||
}
|
||||
// 使用reactive避免ref数据在自动化测试中无法访问
|
||||
const data = reactive({
|
||||
title: 'action-sheet',
|
||||
titleColorCustom: false,
|
||||
itemColorCustom: false,
|
||||
itemContentLarge: false,
|
||||
itemNumLargeSelect: false,
|
||||
cancelTextCustom: false,
|
||||
cancelColorCustom: false,
|
||||
backgroundColorCustom: false,
|
||||
showErrorToast: true,
|
||||
items: [{
|
||||
value: '标题',
|
||||
name: '有标题'
|
||||
},
|
||||
{
|
||||
value: '',
|
||||
name: '无标题'
|
||||
},
|
||||
{
|
||||
value: '超长标题测试内容,测试超过显示最大范围之后的样式-超长标题测试内容,测试超过显示最大范围之后的样式',
|
||||
name: '超长标题'
|
||||
}
|
||||
],
|
||||
current: 0,
|
||||
// #ifdef APP
|
||||
originTheme: null,
|
||||
// #endif
|
||||
} as DataType)
|
||||
|
||||
// #ifdef APP
|
||||
const setThemeAuto = () => {
|
||||
uni.setAppTheme({
|
||||
theme: 'auto'
|
||||
})
|
||||
}
|
||||
|
||||
const resetTheme = () => {
|
||||
const originTheme = data.originTheme
|
||||
if(originTheme != null){
|
||||
uni.setAppTheme({
|
||||
theme: originTheme
|
||||
})
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
const radioChange = (e: UniRadioGroupChangeEvent) => {
|
||||
for (let i = 0; i < data.items.length; i++) {
|
||||
if (data.items[i].value === e.detail.value) {
|
||||
data.current = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const titleColorChange = (e: UniSwitchChangeEvent) => {
|
||||
data.titleColorCustom = e.detail.value
|
||||
}
|
||||
|
||||
const itemContentLargeChange = (e: UniSwitchChangeEvent) => {
|
||||
data.itemContentLarge = e.detail.value
|
||||
}
|
||||
|
||||
const itemColorChange = (e: UniSwitchChangeEvent) => {
|
||||
data.itemColorCustom = e.detail.value
|
||||
}
|
||||
|
||||
const itemNumLargeChange = (e: UniSwitchChangeEvent) => {
|
||||
data.itemNumLargeSelect = e.detail.value
|
||||
}
|
||||
|
||||
const cancelTextChange = (e: UniSwitchChangeEvent) => {
|
||||
data.cancelTextCustom = e.detail.value
|
||||
}
|
||||
|
||||
const cancelColorChange = (e: UniSwitchChangeEvent) => {
|
||||
data.cancelColorCustom = e.detail.value
|
||||
}
|
||||
|
||||
const backgroundColorChange = (e: UniSwitchChangeEvent) => {
|
||||
data.backgroundColorCustom = e.detail.value
|
||||
}
|
||||
|
||||
const showActionSheet = () => {
|
||||
const options: ShowActionSheetOptions = {
|
||||
title: data.items[data.current].value,
|
||||
itemList: ['item1', 'item2', 'item3', 'item4'],
|
||||
success: (res) => {
|
||||
console.log(res.tapIndex);
|
||||
uni.showToast({
|
||||
title: "点击了第" + res.tapIndex + "个选项",
|
||||
icon: "none"
|
||||
})
|
||||
},
|
||||
fail: (error) => {
|
||||
if (data.showErrorToast) {
|
||||
uni.showToast({
|
||||
title: error.errMsg,
|
||||
icon: "none"
|
||||
})
|
||||
}
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
if (data.itemContentLarge) {
|
||||
options.itemList = ['两个黄鹂鸣翠柳,一行白鹭上青天。窗含西岭千秋雪,门泊东吴万里船', '水光潋滟晴方好,山色空蒙雨亦奇。 欲把西湖比西子,淡妆浓抹总相宜', '']
|
||||
}
|
||||
if (data.itemNumLargeSelect) {
|
||||
// 大量选项测试,不能超过6个元素 https://uniapp.dcloud.net.cn/api/ui/prompt.html#showactionsheet
|
||||
const arr: string[] = []
|
||||
for(let i = 0; i < 10; i++){
|
||||
arr.push(`两个黄鹂鸣翠柳,一行白鹭上青天 ${i+1}`)
|
||||
}
|
||||
options.itemList = arr
|
||||
}
|
||||
if(data.titleColorCustom){
|
||||
options.titleColor = '#007AFF'
|
||||
}
|
||||
if(data.itemColorCustom){
|
||||
options.itemColor = '#ff00ff'
|
||||
}
|
||||
if(data.cancelTextCustom){
|
||||
options.cancelText = 'custom cancel'
|
||||
}
|
||||
if(data.cancelColorCustom){
|
||||
options.cancelColor = '#007AFF'
|
||||
}
|
||||
if(data.backgroundColorCustom){
|
||||
options.backgroundColor = '#ccc'
|
||||
}
|
||||
uni.showActionSheet(options)
|
||||
}
|
||||
|
||||
const showActionSheetAndShowAgainInCallback = () => {
|
||||
uni.showActionSheet({
|
||||
title: '第一个',
|
||||
itemList: ['1','2','3'],
|
||||
complete(){
|
||||
uni.showActionSheet({
|
||||
title: '第二个',
|
||||
itemList: ['a','b','c'],
|
||||
complete: (res) => {
|
||||
console.log('showActionSheetAndShowAgainInCallback complete', res)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getLifeCycleNum = () => {
|
||||
return state.lifeCycleNum
|
||||
}
|
||||
|
||||
const setLifeCycleNumFunc = (num: number) => {
|
||||
return setLifeCycleNum(num)
|
||||
}
|
||||
|
||||
// #ifdef WEB
|
||||
const closeWebActionSheet = () => {
|
||||
document.querySelector('.uni-action-sheet_dialog__cell').click()
|
||||
}
|
||||
// #endif
|
||||
|
||||
const hideActionSheet = () => {
|
||||
uni.hideActionSheet()
|
||||
}
|
||||
|
||||
const showActionSheetAndNavigateBackInSuccessCallback = () => {
|
||||
uni.showActionSheet({
|
||||
title: 'showActionSheetAndNavigateBackInSuccessCallback',
|
||||
itemList: ['1','2','3'],
|
||||
success: (res) => {
|
||||
console.log('showActionSheetAndNavigateBackInSuccessCallback success', res)
|
||||
setLifeCycleNum(state.lifeCycleNum + 1)
|
||||
uni.navigateBack()
|
||||
},
|
||||
fail: (error) => {
|
||||
console.log('showActionSheetAndNavigateBackInSuccessCallback fail', error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//TODO: 暂时使用onReady替换onLoad解决当前页面弹两次的问题, modal示例页面未替换,保留该复现问题
|
||||
//ios需要排查解决: uni.openDialogPage方法在页面生命周期onLoad中弹出当前页面的问题,
|
||||
onReady(() => {
|
||||
uni.showActionSheet({
|
||||
title: "onLoad 调用示例,请手动取消",
|
||||
itemList: ['item1', 'item2'],
|
||||
fail: (res) => {
|
||||
// 自动化测试
|
||||
setLifeCycleNum(state.lifeCycleNum + 1)
|
||||
console.log('onLoad showActionSheet fail', res)
|
||||
},
|
||||
complete: (res) => {
|
||||
// 自动化测试
|
||||
setLifeCycleNum(state.lifeCycleNum + 1)
|
||||
console.log('onLoad showActionSheet complete', res)
|
||||
}
|
||||
})
|
||||
// #ifdef APP
|
||||
data.originTheme = uni.getSystemInfoSync().appTheme
|
||||
// #endif
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
data,
|
||||
// #ifdef APP
|
||||
setThemeAuto,
|
||||
resetTheme,
|
||||
// #endif
|
||||
getLifeCycleNum,
|
||||
// #ifdef WEB
|
||||
closeWebActionSheet,
|
||||
// #endif
|
||||
hideActionSheet,
|
||||
setLifeCycleNumFunc,
|
||||
showActionSheetAndNavigateBackInSuccessCallback,
|
||||
showActionSheetAndShowAgainInCallback
|
||||
})
|
||||
</script>
|
||||
在新工单中引用
屏蔽一个用户