diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt
index 644cf4725..ca8b577ec 100644
--- a/tests/qttest/CMakeLists.txt
+++ b/tests/qttest/CMakeLists.txt
@@ -290,6 +290,11 @@ qet_add_app_test(tst_assistantinfopaths tst_assistantinfopaths.cpp)
# %T in a report or cross reference formula is the target folio's title.
qet_add_app_test(tst_reportfoliotitle tst_reportfoliotitle.cpp)
+# The cable cells of a terminal strip are worked out from the cables of
+# the project: wired shows the cable and its core read only, unwired keeps
+# what was typed in, and nothing stale is written into the element.
+qet_add_app_test(tst_terminalcableauto tst_terminalcableauto.cpp)
+
# Escape during a picture's resize, rotate or pivot drag puts it back, keeps
# it selected and records no undo step (#1414); the key goes to the view.
qet_add_app_test(tst_imagehandleescape tst_imagehandleescape.cpp)
diff --git a/tests/qttest/tst_terminalcableauto.cpp b/tests/qttest/tst_terminalcableauto.cpp
new file mode 100644
index 000000000..c82a4c8cd
--- /dev/null
+++ b/tests/qttest/tst_terminalcableauto.cpp
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ Copyright 2006-2026 The QElectroTech Team
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+#include "qetapptest.h"
+#include "TerminalStrip/realterminal.h"
+#include "TerminalStrip/terminalstrip.h"
+#include "TerminalStrip/ui/terminalstripmodel.h"
+#include "cable/cable.h"
+#include "qetgraphicsitem/conductor.h"
+#include "qetgraphicsitem/element.h"
+#include "qetgraphicsitem/terminal.h"
+#include "qetproject.h"
+
+/**
+ The Cable and Color / wire number columns of the terminal strip editor
+ are worked out from the cables of the project: a terminal with a cable
+ wired to it shows that cable and its core, the cell is read only, and
+ nothing is written into the element -- so a cable renamed or removed
+ cannot leave a stale value behind. A terminal no cable is wired to
+ keeps the value typed in by hand, cell and all.
+
+ fixtures/every_feature.qet has the strip X1 whose two terminals are
+ wired to conductors on the folio, and no cable at all.
+*/
+class tst_terminalcableauto : public QObject
+{
+ Q_OBJECT
+
+ // The wired terminal of strip X1: its element carries a conductor.
+ static QSharedPointer wiredTerminal(QETProject &project)
+ {
+ const QVector strips = project.terminalStrip();
+ if (strips.isEmpty()) return {};
+ for (const QSharedPointer &real_t
+ : strips.first()->realTerminals())
+ {
+ Element *element = real_t ? real_t->element() : nullptr;
+ if (!element) continue;
+ for (Terminal *terminal : element->terminals())
+ if (terminal && !terminal->conductors().isEmpty())
+ return real_t;
+ }
+ return {};
+ }
+
+ static Conductor *conductorOf(const QSharedPointer &real_t)
+ {
+ Element *element = real_t->element();
+ if (!element) return nullptr;
+ for (Terminal *terminal : element->terminals()) {
+ if (!terminal) continue;
+ const QList conductors = terminal->conductors();
+ if (!conductors.isEmpty()) return conductors.first();
+ }
+ return nullptr;
+ }
+
+ // The cable the create dialog hands over: owned by the project, four
+ // cores, core 1 (blue) wired to the terminal's conductor.
+ static Cable *wireCable(QETProject &project,
+ const QSharedPointer &real_t,
+ int core = 1)
+ {
+ Cable *cable = project.newCable();
+ cable->setDesignation(QStringLiteral("15W1"));
+ cable->setCoreCount(4);
+ cable->setCoreColors({QStringLiteral("bn"), QStringLiteral("bl"),
+ QStringLiteral("gn/ye"), QStringLiteral("gy")});
+ CableCore assignment;
+ assignment.core = core;
+ assignment.conductor = conductorOf(real_t)->uuid();
+ cable->setCore(assignment);
+ return cable;
+ }
+
+private slots:
+ void wiredCableIsWorkedOutAndReadsOnly()
+ {
+ const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
+ QVERIFY2(!fixture.isEmpty(), "fixture project not found");
+ QETProject project(fixture);
+ QCOMPARE(project.state(), QETProject::Ok);
+
+ const auto real_t = wiredTerminal(project);
+ QVERIFY2(!real_t.isNull(), "the fixture has a wired terminal");
+ Element *element = real_t->element();
+
+ //Without a cable, the cells show nothing and may be typed in
+ QVERIFY(!real_t->cableIsAutomatic());
+ TerminalStripModel model_before(project.terminalStrip().first());
+ QVERIFY(model_before.rowCount() > 0);
+ QVERIFY(model_before.flags(model_before.index(0, TerminalStripModel::Cable))
+ & Qt::ItemIsEditable);
+
+ wireCable(project, real_t);
+
+ //The terminal itself reads the cable and its core
+ QCOMPARE(real_t->cable(), QStringLiteral("15W1"));
+ QVERIFY(real_t->cableIsAutomatic());
+ QCOMPARE(real_t->cableWire(), QStringLiteral("bl"));
+
+ //The automatic value is never written into the element: nothing
+ //stays behind once the cable is renamed or removed
+ QVERIFY(element);
+ QVERIFY(element->elementData().m_informations
+ .value(RealTerminal::cableInfoKey()).toString().isEmpty());
+
+ //The model shows both cells and keeps them out of the edits
+ TerminalStripModel model(project.terminalStrip().first());
+ QCOMPARE(model.rowCount(), model_before.rowCount());
+ const QModelIndex cable_cell = model.index(0, TerminalStripModel::Cable);
+ const QModelIndex wire_cell = model.index(0, TerminalStripModel::CableWire);
+ QCOMPARE(model.data(cable_cell).toString(), QStringLiteral("15W1"));
+ QCOMPARE(model.data(wire_cell).toString(), QStringLiteral("bl"));
+ QVERIFY(!(model.flags(cable_cell) & Qt::ItemIsEditable));
+ QVERIFY(!(model.flags(wire_cell) & Qt::ItemIsEditable));
+ //The other cells go on being editable
+ QVERIFY(model.flags(model.index(0, TerminalStripModel::Label))
+ & Qt::ItemIsEditable);
+ }
+
+ void coreWithoutColorIsShownAsItsNumber()
+ {
+ const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
+ QETProject project(fixture);
+ QCOMPARE(project.state(), QETProject::Ok);
+
+ const auto real_t = wiredTerminal(project);
+ QVERIFY(!real_t.isNull());
+
+ Cable *cable = project.newCable();
+ cable->setDesignation(QStringLiteral("15W1"));
+ cable->setCoreCount(4);
+ //A type file which gives no colours: the number of the core is shown
+ CableCore assignment;
+ assignment.core = 1;
+ assignment.conductor = conductorOf(real_t)->uuid();
+ cable->setCore(assignment);
+
+ QCOMPARE(real_t->cable(), QStringLiteral("15W1"));
+ QCOMPARE(real_t->cableWire(), QStringLiteral("2"));
+ QVERIFY(real_t->cableIsAutomatic());
+ }
+
+ void typedValueStaysWhenNoCableIsThere()
+ {
+ const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
+ QETProject project(fixture);
+ QCOMPARE(project.state(), QETProject::Ok);
+
+ const auto real_t = wiredTerminal(project);
+ QVERIFY(!real_t.isNull());
+ Element *element = real_t->element();
+ QVERIFY(element);
+
+ //A cable designation typed in by hand in the editor
+ ElementData typed = element->elementData();
+ typed.m_informations.addValue(RealTerminal::cableInfoKey(),
+ QStringLiteral("K9"));
+ element->setElementData(typed);
+ QCOMPARE(real_t->cable(), QStringLiteral("K9"));
+ QVERIFY(!real_t->cableIsAutomatic());
+
+ //Wired to a cable: the cable is shown, the typed value is set aside
+ Cable *cable = wireCable(project, real_t);
+ QCOMPARE(real_t->cable(), QStringLiteral("15W1"));
+ QVERIFY(real_t->cableIsAutomatic());
+ QCOMPARE(real_t->cableWire(), QStringLiteral("bl"));
+
+ //Cable removed: the typed value is back, no stale 15W1 anywhere
+ cable->removeCore(1);
+ QCOMPARE(real_t->cable(), QStringLiteral("K9"));
+ QVERIFY(!real_t->cableIsAutomatic());
+ QVERIFY(element->elementData().m_informations
+ .value(RealTerminal::cableInfoKey())
+ .toString() == QStringLiteral("K9"));
+
+ TerminalStripModel model(project.terminalStrip().first());
+ QVERIFY(model.flags(model.index(0, TerminalStripModel::Cable))
+ & Qt::ItemIsEditable);
+ }
+};
+
+QET_APP_TEST_MAIN(tst_terminalcableauto)
+
+#include "tst_terminalcableauto.moc"