EXAMPLES =
List.of("λx.x", "λx.λy.y x", "λx.λy.y (x x)", "let f = λx. g y y in f 3", "(λx.x x) (λx.x x)");
private final Paragraph instruction;
@@ -39,9 +41,11 @@ public class ExampleDialog extends Dialog implements LocaleChangeObserver {
callback.accept(term);
this.close();
});
+ button.setId(term); // needed for IT
layout.add(button);
}
add(layout);
+ setId(EXAMPLE_DIALOG_ID);
}
@Override
diff --git a/src/main/java/edu/kit/typicalc/view/main/InputBar.java b/src/main/java/edu/kit/typicalc/view/main/InputBar.java
index 8229aff..a3a7ec9 100644
--- a/src/main/java/edu/kit/typicalc/view/main/InputBar.java
+++ b/src/main/java/edu/kit/typicalc/view/main/InputBar.java
@@ -31,6 +31,8 @@ public class InputBar extends HorizontalLayout implements LocaleChangeObserver {
*/
private static final String INPUT_FIELD_ID = "inputField";
private static final String INPUT_BAR_ID = "inputBar";
+ private static final String INFER_BUTTON_ID = "inferButton";
+ private static final String EXAMPLE_BUTTON_ID = "exampleButton";
private static final short MAX_INPUT_LENGTH = 1000;
@@ -56,9 +58,11 @@ public class InputBar extends HorizontalLayout implements LocaleChangeObserver {
inputField.addValueChangeListener(event -> onInputFieldValueChange());
lambdaButton = new Button(getTranslation("root.lambda"), event -> onlambdaButtonClick());
exampleButton = new Button(getTranslation("root.examplebutton"), event -> onExampleButtonClick());
+ exampleButton.setId(EXAMPLE_BUTTON_ID);
inferTypeButton = new Button(getTranslation("root.typeInfer"), event -> onTypeInferButtonClick(callback));
inferTypeButton.addClickShortcut(Key.ENTER).listenOn(this);
inferTypeButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
+ inferTypeButton.setId(INFER_BUTTON_ID);
add(infoIcon, exampleButton, lambdaButton, inputField, inferTypeButton);
setId(INPUT_BAR_ID);
diff --git a/src/main/java/edu/kit/typicalc/view/main/UpperBar.java b/src/main/java/edu/kit/typicalc/view/main/UpperBar.java
index e42eaeb..341e7b8 100644
--- a/src/main/java/edu/kit/typicalc/view/main/UpperBar.java
+++ b/src/main/java/edu/kit/typicalc/view/main/UpperBar.java
@@ -77,10 +77,10 @@ public class UpperBar extends HorizontalLayout {
*/
protected void typeInfer(final String lambdaString) {
inputBar.reset(); //TODO should term remain in input field?
+
+ presenter.typeInferLambdaString(lambdaString, new HashMap<>());
if (lambdaString.equals(StringUtils.EMPTY)) {
routeToStartPage();
- } else {
- presenter.typeInferLambdaString(lambdaString, new HashMap<>());
}
}
diff --git a/src/test/java/edu/kit/typicalc/view/AbstractIT.java b/src/test/java/edu/kit/typicalc/view/AbstractIT.java
index 117377f..a80915c 100644
--- a/src/test/java/edu/kit/typicalc/view/AbstractIT.java
+++ b/src/test/java/edu/kit/typicalc/view/AbstractIT.java
@@ -6,6 +6,7 @@ import org.junit.Rule;
import com.vaadin.testbench.IPAddress;
import com.vaadin.testbench.ScreenshotOnFailureRule;
import com.vaadin.testbench.TestBenchTestCase;
+
import org.openqa.selenium.firefox.FirefoxDriver;
/**
@@ -21,7 +22,7 @@ public abstract class AbstractIT extends TestBenchTestCase {
@Before
public void setUp() {
setDriver(new FirefoxDriver());
- getDriver().get("http://127.0.0.1:8080");
+ getDriver().get("http://" + IPAddress.findSiteLocalAddress() + ":8080");
}
}
diff --git a/src/test/java/edu/kit/typicalc/view/ScreenshotIT.java b/src/test/java/edu/kit/typicalc/view/ScreenshotIT.java
index a3528d2..a8956a4 100644
--- a/src/test/java/edu/kit/typicalc/view/ScreenshotIT.java
+++ b/src/test/java/edu/kit/typicalc/view/ScreenshotIT.java
@@ -1,23 +1,27 @@
package edu.kit.typicalc.view;
import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.io.IOException;
-import edu.kit.typicalc.view.main.MainViewImpl;
import org.junit.Test;
import org.openqa.selenium.HasCapabilities;
import com.vaadin.testbench.Parameters;
import com.vaadin.testbench.commands.TestBenchCommandExecutor;
+import edu.kit.typicalc.view.pageobjects.InputBarElement;
+
/**
* This example contains usage examples of screenshot comparison feature.
*
*/
public class ScreenshotIT extends AbstractIT {
+ private static final String IDENTITY_TERM = "λx.x";
+
/**
* We'll want to perform some additional setup functions, so we override the
* setUp() method.
@@ -52,7 +56,25 @@ public class ScreenshotIT extends AbstractIT {
+ " for error images",
testBench().compareScreen("initialView"));
}
-
+
+ @Test
+ public void basicExecution() throws Exception {
+ //TODO take screenshot and add to proper folder
+ InputBarElement inputBar = $(InputBarElement.class).first();
+ inputBar.setCurrentValue(IDENTITY_TERM);
+
+ assertEquals(IDENTITY_TERM, inputBar.getCurrentValue());
+
+ inputBar.typeInfer();
+ TestBenchCommandExecutor executer = getCommandExecutor();
+ executer.waitForVaadin();
+
+ assertTrue("Screenshot comparison for 'identityView' failed, see "
+ + Parameters.getScreenshotErrorDirectory()
+ + " for error images",
+ testBench().compareScreen("identityView"));
+ }
+
/**
* Generates a reference screenshot if no reference exists.
*
diff --git a/src/test/java/edu/kit/typicalc/view/ViewMainIT.java b/src/test/java/edu/kit/typicalc/view/ViewMainIT.java
new file mode 100644
index 0000000..32d83fb
--- /dev/null
+++ b/src/test/java/edu/kit/typicalc/view/ViewMainIT.java
@@ -0,0 +1,67 @@
+package edu.kit.typicalc.view;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import edu.kit.typicalc.model.parser.ParseError;
+import edu.kit.typicalc.view.pageobjects.ErrorNotificationElement;
+import edu.kit.typicalc.view.pageobjects.ExampleDialogElement;
+import edu.kit.typicalc.view.pageobjects.InputBarElement;
+
+public class ViewMainIT extends AbstractIT {
+
+ //TODO change to real Value
+ private static final String EMPTY_INPUT_ERROR = "?[" + "root." + ParseError.TOO_FEW_TOKENS.toString() + "]?";
+ private static final String OVERLONG_INPUT_ERROR = "Die maximale Länge der Eingabe beträgt 1000 Zeichen!";
+ private static final String INPUT_EXAMPLE = "let f = λx. g y y in f 3";
+
+ @Test
+ public void emptyInput() {
+ InputBarElement inputBar = $(InputBarElement.class).first();
+ inputBar.setCurrentValue(StringUtils.EMPTY);
+
+ assertEquals(StringUtils.EMPTY, inputBar.getCurrentValue());
+ inputBar.typeInfer();
+
+ ErrorNotificationElement errorNotification = $(ErrorNotificationElement.class).waitForFirst();
+ assertTrue(errorNotification.isOpen());
+ String errorMessage = errorNotification.getErrorSpan().getText();
+ assertEquals(EMPTY_INPUT_ERROR, errorMessage);
+
+ errorNotification.close();
+ assertFalse(errorNotification.isOpen());
+ }
+
+ @Ignore
+ @Test
+ public void overlongInput() {
+ //TODO only works when executed separately, fix bug
+ InputBarElement inputBar = $(InputBarElement.class).first();
+ inputBar.setCurrentValue(new String(new char[1000]));
+ inputBar.typeInfer();
+
+ ErrorNotificationElement errorNotification = $(ErrorNotificationElement.class).waitForFirst();
+ assertTrue(errorNotification.isOpen());
+ String errorMessage = errorNotification.getErrorSpan().getText();
+ assertEquals(OVERLONG_INPUT_ERROR, errorMessage);
+
+ errorNotification.close();
+ assertFalse(errorNotification.isOpen());
+ }
+
+ @Test
+ public void chooseExample() {
+ InputBarElement inputBar = $(InputBarElement.class).first();
+ inputBar.openExampleDialog();
+
+ ExampleDialogElement exampleDialog = $(ExampleDialogElement.class).waitForFirst();
+ exampleDialog.insertExample(INPUT_EXAMPLE);
+
+ assertEquals(INPUT_EXAMPLE, inputBar.getCurrentValue());
+ }
+}
diff --git a/src/test/java/edu/kit/typicalc/view/pageobjects/ErrorNotificationElement.java b/src/test/java/edu/kit/typicalc/view/pageobjects/ErrorNotificationElement.java
new file mode 100644
index 0000000..821b287
--- /dev/null
+++ b/src/test/java/edu/kit/typicalc/view/pageobjects/ErrorNotificationElement.java
@@ -0,0 +1,19 @@
+package edu.kit.typicalc.view.pageobjects;
+
+import com.vaadin.flow.component.button.testbench.ButtonElement;
+import com.vaadin.flow.component.html.testbench.SpanElement;
+import com.vaadin.flow.component.notification.testbench.NotificationElement;
+import com.vaadin.flow.component.orderedlayout.testbench.VerticalLayoutElement;
+import com.vaadin.testbench.annotations.Attribute;
+
+@Attribute(name = "id", value = "errorNotification")
+public class ErrorNotificationElement extends NotificationElement {
+
+ public void close() {
+ $(ButtonElement.class).first().click();
+ }
+
+ public SpanElement getErrorSpan() {
+ return $(VerticalLayoutElement.class).first().$(SpanElement.class).first();
+ }
+}
diff --git a/src/test/java/edu/kit/typicalc/view/pageobjects/ExampleDialogElement.java b/src/test/java/edu/kit/typicalc/view/pageobjects/ExampleDialogElement.java
new file mode 100644
index 0000000..44c7c18
--- /dev/null
+++ b/src/test/java/edu/kit/typicalc/view/pageobjects/ExampleDialogElement.java
@@ -0,0 +1,14 @@
+package edu.kit.typicalc.view.pageobjects;
+
+import com.vaadin.flow.component.button.testbench.ButtonElement;
+import com.vaadin.flow.component.dialog.testbench.DialogElement;
+import com.vaadin.flow.component.orderedlayout.testbench.VerticalLayoutElement;
+import com.vaadin.testbench.annotations.Attribute;
+
+@Attribute(name = "id", value = "exampleDialog")
+public class ExampleDialogElement extends DialogElement {
+
+ public void insertExample(String example) {
+ $(VerticalLayoutElement.class).first().$(ButtonElement.class).id(example).click();
+ }
+}
diff --git a/src/test/java/edu/kit/typicalc/view/pageobjects/InputBarElement.java b/src/test/java/edu/kit/typicalc/view/pageobjects/InputBarElement.java
new file mode 100644
index 0000000..8aa13b3
--- /dev/null
+++ b/src/test/java/edu/kit/typicalc/view/pageobjects/InputBarElement.java
@@ -0,0 +1,26 @@
+package edu.kit.typicalc.view.pageobjects;
+
+import com.vaadin.flow.component.button.testbench.ButtonElement;
+import com.vaadin.flow.component.orderedlayout.testbench.HorizontalLayoutElement;
+import com.vaadin.flow.component.textfield.testbench.TextFieldElement;
+import com.vaadin.testbench.annotations.Attribute;
+
+@Attribute(name = "id", value = "inputBar") // maybe make id constants public to use the here
+public class InputBarElement extends HorizontalLayoutElement {
+
+ public void typeInfer() {
+ $(ButtonElement.class).id("inferButton").click();
+ }
+
+ public void setCurrentValue(String value) {
+ $(TextFieldElement.class).id("inputField").setValue(value);
+ }
+
+ public String getCurrentValue() {
+ return $(TextFieldElement.class).id("inputField").getValue();
+ }
+
+ public void openExampleDialog() {
+ $(ButtonElement.class).id("exampleButton").click();
+ }
+}
diff --git a/src/test/resources/screenshots/initialView_windows_chrome_88.png b/src/test/resources/screenshots/initialView_windows_chrome_88.png
new file mode 100644
index 0000000000000000000000000000000000000000..f999854984763842b1549d2b0c25f82b739f4fab
GIT binary patch
literal 20963
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%0D)zTr}`;*7VivhzAGG_4<8;w))tW>Bw+aqj|~)
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