diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index e3c6eaa8f6..e56be05ad2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -58,14 +58,14 @@ body: - label: "I have saved the log as a `.txt` file and attached it below (DON'T PASTE!)." required: true - - type: textarea + - type: upload id: debug_log_upload attributes: - label: "Debug Log Upload (Drag & Drop .txt file here)" - description: "DO NOT PASTE! Just drag and drop your .txt file into this field." - placeholder: "Drag & drop file here. DO NOT PASTE!" + label: "Debug Log Upload (.txt file required)" + description: "Upload the debug log as a .txt file. Pasted logs or plain text are not accepted." validations: required: true + accept: ".txt" - type: markdown attributes: diff --git a/README.md b/README.md index a6e7c3967c..2327da6c54 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,11 @@ This feature only works when map creation is enabled in the adapter options. Ope Placeholder for the next version (at the beginning of the line): ### **WORK IN PROGRESS** --> +### **WORK IN PROGRESS** + +* (copystring) Fixed missing auto-empty command for Roborock Qrevo MaxV (#1272). +* (copystring) Require bug reports to upload a `.txt` debug log file. + ### 0.7.1 (2026-05-19) * (copystring) Fixed local TCP recovery when a Roborock device gets a new LAN IP address. @@ -107,7 +112,9 @@ This feature only works when map creation is enabled in the adapter options. Ope * (copystring) Update LICENSE * (copystring) Update README.md -Older changes can be found in [CHANGELOG_OLD.md](CHANGELOG_OLD.md).## License +Older changes can be found in [CHANGELOG_OLD.md](CHANGELOG_OLD.md). + +## License MIT License Copyright (c) 2025-2026 copystring diff --git a/src/lib/features/vacuum/a87_features.ts b/src/lib/features/vacuum/a87_features.ts index f6eef4b4d8..5edd769515 100644 --- a/src/lib/features/vacuum/a87_features.ts +++ b/src/lib/features/vacuum/a87_features.ts @@ -38,7 +38,8 @@ const a87Config: DeviceModelConfig = { Feature.Rdt, Feature.CleanArea, Feature.CleanTime, - Feature.SwitchStatus + Feature.SwitchStatus, + Feature.AutoEmptyDock ] }; diff --git a/src/lib/features/vacuum/registeredModelFeatures.test.ts b/src/lib/features/vacuum/registeredModelFeatures.test.ts new file mode 100644 index 0000000000..c5d7df1ae0 --- /dev/null +++ b/src/lib/features/vacuum/registeredModelFeatures.test.ts @@ -0,0 +1,65 @@ +import { describe, expect, it, vi } from "vitest"; +import { BaseDeviceFeatures, type FeatureDependencies } from "../baseDeviceFeatures"; +import { Feature } from "../features.enum"; +import "./index"; + +describe("registered vacuum model features", () => { + function createDependencies(): FeatureDependencies { + const requestsHandlerMock = { + sendRequest: vi.fn().mockResolvedValue({}), + command: vi.fn().mockResolvedValue(undefined), + mapParser: { parsedata: vi.fn().mockResolvedValue({}) }, + mapCreator: { canvasMap: vi.fn().mockResolvedValue(["", "", ""]) } + }; + + const adapterMock = { + namespace: "roborock.0", + log: { info: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn(), silly: vi.fn() }, + setStateChanged: vi.fn().mockResolvedValue(undefined), + setState: vi.fn(), + ensureState: vi.fn().mockResolvedValue(undefined), + ensureFolder: vi.fn().mockResolvedValue(undefined), + getStateAsync: vi.fn().mockResolvedValue(undefined), + getStatesAsync: vi.fn().mockResolvedValue({}), + getObjectAsync: vi.fn().mockResolvedValue(undefined), + extendObject: vi.fn().mockResolvedValue(undefined), + setObject: vi.fn().mockResolvedValue(undefined), + setObjectNotExistsAsync: vi.fn().mockResolvedValue(undefined), + requestsHandler: requestsHandlerMock, + getDeviceProtocolVersion: vi.fn().mockResolvedValue("1.0"), + translations: {}, + http_api: { + getFwFeaturesResult: vi.fn(), + storeFwFeaturesResult: vi.fn(), + getRobotModel: vi.fn().mockReturnValue("roborock.vacuum.a87"), + getDevices: vi.fn().mockReturnValue([]) + }, + rLog: vi.fn(), + translationManager: { + get: vi.fn().mockImplementation((key, def) => def || key) + }, + errorMessage: (error: unknown) => error instanceof Error ? error.message : String(error) + }; + + return { + adapter: adapterMock, + http_api: adapterMock.http_api, + ensureState: vi.fn().mockResolvedValue(undefined), + ensureFolder: vi.fn().mockResolvedValue(undefined), + log: adapterMock.log, + config: { staticFeatures: [] } + } as unknown as FeatureDependencies; + } + + it("exposes the auto-empty command for Qrevo MaxV through the model registry", async () => { + const ModelClass = BaseDeviceFeatures.getRegisteredModelClass("roborock.vacuum.a87"); + expect(ModelClass).toBeDefined(); + if (!ModelClass) throw new Error("roborock.vacuum.a87 is not registered"); + + const vacuum = new ModelClass(createDependencies(), "duid1"); + await vacuum.initialize(); + + expect(vacuum.hasStaticFeature(Feature.AutoEmptyDock)).toBe(true); + expect(vacuum.commands).toHaveProperty("app_start_dust_collection"); + }); +});