chore: Typescript: Rewrite tests (#21723)
Co-authored-by: Michael Geers <michael@geers.tv>
This commit is contained in:
parent
fda3b066db
commit
d43ab9fa6a
53 changed files with 2287 additions and 2154 deletions
|
|
@ -1,103 +0,0 @@
|
|||
import bodyParser from "body-parser";
|
||||
|
||||
let state = {
|
||||
site: {
|
||||
grid: { power: 0 },
|
||||
pv: { power: 0 },
|
||||
battery: { power: 0, soc: 0 },
|
||||
},
|
||||
loadpoints: [{ power: 0, energy: 0, enabled: false, status: "A" }],
|
||||
vehicles: [{ soc: 0, range: 0 }],
|
||||
};
|
||||
|
||||
const loggingMiddleware = (req, res, next) => {
|
||||
console.log(`[simulator] ${req.method} ${req.originalUrl}`);
|
||||
next();
|
||||
};
|
||||
|
||||
const stateApiMiddleware = (req, res, next) => {
|
||||
if (req.method === "POST" && req.originalUrl === "/api/state") {
|
||||
console.log("[simulator] POST /api/state");
|
||||
state = req.body;
|
||||
res.end();
|
||||
} else if (req.method === "POST" && req.originalUrl === "/api/shutdown") {
|
||||
console.log("[simulator] POST /api/shutdown");
|
||||
res.end();
|
||||
process.exit();
|
||||
} else if (req.originalUrl === "/api/state") {
|
||||
res.end(JSON.stringify(state));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const openemsMiddleware = (req, res, next) => {
|
||||
const endpoints = {
|
||||
"/rest/channel/_sum/GridActivePower": { value: state.site.grid.power },
|
||||
"/rest/channel/_sum/ProductionActivePower": { value: state.site.pv.power },
|
||||
"/rest/channel/_sum/EssDischargePower": { value: state.site.battery.power },
|
||||
"/rest/channel/_sum/EssSoc": { value: state.site.battery.soc },
|
||||
};
|
||||
const endpoint = endpoints[req.originalUrl];
|
||||
if (req.method === "GET" && endpoint) {
|
||||
console.log("[simulator] GET", req.originalUrl);
|
||||
res.end(JSON.stringify(endpoint));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const teslaloggerMiddleware = (req, res, next) => {
|
||||
if (req.method === "GET" && req.originalUrl.startsWith("/currentjson/")) {
|
||||
const id = parseInt(req.originalUrl.split("/")[2]);
|
||||
const vehicle = state.vehicles[id - 1];
|
||||
if (!vehicle) {
|
||||
res.statusCode = 404;
|
||||
res.end(JSON.stringify({ error: "Vehicle not found" }));
|
||||
return;
|
||||
}
|
||||
const data = {
|
||||
battery_level: vehicle.soc,
|
||||
battery_range_km: vehicle.range,
|
||||
plugged_in: true,
|
||||
charging: false,
|
||||
odometer: 10000,
|
||||
is_preconditioning: false,
|
||||
charge_current_request: 10,
|
||||
};
|
||||
res.end(JSON.stringify(data));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const shellyMiddleware = (req, res, next) => {
|
||||
// simulate a shelly gen2 switch device api. implement power and energy
|
||||
if (req.originalUrl === "/shelly") {
|
||||
res.end(JSON.stringify({ gen: 2 }));
|
||||
} else if (req.originalUrl === "/rpc/Shelly.ListMethods") {
|
||||
res.end(JSON.stringify({ methods: ["Switch.GetStatus"] }));
|
||||
} else if (req.originalUrl === "/rpc/Switch.GetStatus?id=0") {
|
||||
res.end(
|
||||
JSON.stringify({ apower: state.site.pv.power, aenergy: { total: state.site.pv.energy } })
|
||||
);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
export default () => ({
|
||||
name: "api",
|
||||
enforce: "pre",
|
||||
configureServer(server) {
|
||||
console.log("[simulator] configured");
|
||||
return () => {
|
||||
server.middlewares.use(loggingMiddleware);
|
||||
server.middlewares.use(bodyParser.json());
|
||||
server.middlewares.use(stateApiMiddleware);
|
||||
server.middlewares.use(openemsMiddleware);
|
||||
server.middlewares.use(teslaloggerMiddleware);
|
||||
server.middlewares.use(shellyMiddleware);
|
||||
};
|
||||
},
|
||||
});
|
||||
129
tests/simulator/api.ts
Normal file
129
tests/simulator/api.ts
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
import bodyParser from "body-parser";
|
||||
import type { Connect, ViteDevServer } from "vite";
|
||||
import type { ServerResponse } from "http";
|
||||
|
||||
let state = {
|
||||
site: {
|
||||
grid: { power: 0 },
|
||||
pv: { power: 0, energy: 0 },
|
||||
battery: { power: 0, soc: 0 },
|
||||
},
|
||||
loadpoints: [{ power: 0, energy: 0, enabled: false, status: "A" }],
|
||||
vehicles: [{ soc: 0, range: 0 }],
|
||||
};
|
||||
|
||||
const loggingMiddleware = (
|
||||
req: Connect.IncomingMessage,
|
||||
_: ServerResponse,
|
||||
next: Connect.NextFunction
|
||||
) => {
|
||||
console.log(`[simulator] ${req.method} ${req.url}`);
|
||||
next();
|
||||
};
|
||||
|
||||
const stateApiMiddleware = (
|
||||
req: Connect.IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next: Connect.NextFunction
|
||||
) => {
|
||||
if (req.method === "POST" && req.originalUrl === "/api/state") {
|
||||
console.log("[simulator] POST /api/state");
|
||||
// @ts-expect-error Property 'body' does not exist on type 'IncomingMessage'
|
||||
state = req.body;
|
||||
res.end();
|
||||
} else if (req.method === "POST" && req.originalUrl === "/api/shutdown") {
|
||||
console.log("[simulator] POST /api/shutdown");
|
||||
res.end();
|
||||
process.exit();
|
||||
} else if (req.originalUrl === "/api/state") {
|
||||
res.end(JSON.stringify(state));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const openemsMiddleware = (
|
||||
req: Connect.IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next: Connect.NextFunction
|
||||
) => {
|
||||
const endpoints = {
|
||||
"/rest/channel/_sum/GridActivePower": { value: state.site.grid.power },
|
||||
"/rest/channel/_sum/ProductionActivePower": { value: state.site.pv.power },
|
||||
"/rest/channel/_sum/EssDischargePower": { value: state.site.battery.power },
|
||||
"/rest/channel/_sum/EssSoc": { value: state.site.battery.soc },
|
||||
};
|
||||
const endpoint = endpoints[req.originalUrl as keyof typeof endpoints];
|
||||
if (req.method === "GET" && endpoint) {
|
||||
console.log("[simulator] GET", req.originalUrl);
|
||||
res.end(JSON.stringify(endpoint));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const teslaloggerMiddleware = (
|
||||
req: Connect.IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next: Connect.NextFunction
|
||||
) => {
|
||||
if (req.method === "GET" && req.originalUrl && req.originalUrl.startsWith("/currentjson/")) {
|
||||
const id = parseInt(req.originalUrl.split("/")[2]);
|
||||
const vehicle = state.vehicles[id - 1];
|
||||
if (!vehicle) {
|
||||
res.statusCode = 404;
|
||||
res.end(JSON.stringify({ error: "Vehicle not found" }));
|
||||
return;
|
||||
}
|
||||
const data = {
|
||||
battery_level: vehicle.soc,
|
||||
battery_range_km: vehicle.range,
|
||||
plugged_in: true,
|
||||
charging: false,
|
||||
odometer: 10000,
|
||||
is_preconditioning: false,
|
||||
charge_current_request: 10,
|
||||
};
|
||||
res.end(JSON.stringify(data));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
const shellyMiddleware = (
|
||||
req: Connect.IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next: Connect.NextFunction
|
||||
) => {
|
||||
// simulate a shelly gen2 switch device api. implement power and energy
|
||||
if (req.originalUrl === "/shelly") {
|
||||
res.end(JSON.stringify({ gen: 2 }));
|
||||
} else if (req.originalUrl === "/rpc/Shelly.ListMethods") {
|
||||
res.end(JSON.stringify({ methods: ["Switch.GetStatus"] }));
|
||||
} else if (req.originalUrl === "/rpc/Switch.GetStatus?id=0") {
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
apower: state.site.pv.power,
|
||||
aenergy: { total: state.site.pv.energy },
|
||||
})
|
||||
);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
export default () => ({
|
||||
name: "api",
|
||||
enforce: "pre",
|
||||
configureServer(server: ViteDevServer) {
|
||||
console.log("[simulator] configured");
|
||||
return () => {
|
||||
server.middlewares.use(loggingMiddleware);
|
||||
server.middlewares.use(bodyParser.json());
|
||||
server.middlewares.use(stateApiMiddleware);
|
||||
server.middlewares.use(openemsMiddleware);
|
||||
server.middlewares.use(teslaloggerMiddleware);
|
||||
server.middlewares.use(shellyMiddleware);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
@ -239,14 +239,28 @@
|
|||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import axios from "axios";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: "Simulator",
|
||||
data() {
|
||||
return {
|
||||
state: null,
|
||||
state: null as {
|
||||
site: {
|
||||
grid: { power: number };
|
||||
pv: { power: number; energy: number };
|
||||
battery: { power: number; soc: number };
|
||||
};
|
||||
loadpoints: {
|
||||
power: number;
|
||||
energy: number;
|
||||
enabled: boolean;
|
||||
status: string;
|
||||
}[];
|
||||
vehicles: { soc: number; range: number }[];
|
||||
} | null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -262,24 +276,24 @@ export default {
|
|||
},
|
||||
addVehicle() {
|
||||
// push a duplacate of the last entry
|
||||
this.state.vehicles.push({
|
||||
this.state?.vehicles.push({
|
||||
...this.state.vehicles[this.state.vehicles.length - 1],
|
||||
});
|
||||
},
|
||||
removeVehicle(index) {
|
||||
this.state.vehicles.splice(index, 1);
|
||||
removeVehicle(index: number) {
|
||||
this.state?.vehicles.splice(index, 1);
|
||||
},
|
||||
addLoadpoint() {
|
||||
// push a duplacate of the last entry
|
||||
this.state.loadpoints.push({
|
||||
this.state?.loadpoints.push({
|
||||
...this.state.loadpoints[this.state.loadpoints.length - 1],
|
||||
});
|
||||
},
|
||||
removeLoadpoint(index) {
|
||||
this.state.loadpoints.splice(index, 1);
|
||||
removeLoadpoint(index: number) {
|
||||
this.state?.loadpoints.splice(index, 1);
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import api from "./api";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue(), api()],
|
||||
server: { port: 7072, host: true },
|
||||
});
|
||||
12
tests/simulator/vite.config.ts
Normal file
12
tests/simulator/vite.config.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import api from "./api";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
// @ts-expect-error the in api() declared 'enforce' property is not supported in TypeScript but in JavaScript
|
||||
api(),
|
||||
],
|
||||
server: { port: 7072, host: true },
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue