Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSE-792 Fix: No Indentation on JSON Resource Model Edit Page #8719

Merged
merged 9 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.rundeck.tests.functional.selenium

import org.rundeck.tests.functional.selenium.pages.EditNodesFilePage
import org.rundeck.tests.functional.selenium.pages.EditNodesPage
import org.rundeck.tests.functional.selenium.pages.LoginPage
import org.rundeck.tests.functional.selenium.pages.ProjectHomePage
import org.rundeck.tests.functional.selenium.pages.ProjectListPage
import org.rundeck.util.annotations.SeleniumCoreTest
import org.rundeck.util.container.SeleniumBase

import java.util.stream.Collectors

@SeleniumCoreTest
class AceEditorSpec extends SeleniumBase{

private static def projectName = 'resourcesTest'
private static def jsonFileIndex = 2

def setupSpec(){
setupProjectWithNodes(projectName, "/projects-import/resourcesTest.zip")
}

def "Edit json file resource model with indented text"(){

// 1. Upload a project with a (json) file resource model created
// 2. Attempt to modify the file (Ace Editor rendered into view)
// Asserts the JSON is indented.

setup:
LoginPage loginPage = page LoginPage
ProjectHomePage projectHomePage = page ProjectHomePage
EditNodesPage editNodesPage = page EditNodesPage
editNodesPage.setProject(projectName)
EditNodesFilePage editNodesFilePage = page EditNodesFilePage
editNodesFilePage.setProject(projectName)
editNodesFilePage.setIndex(jsonFileIndex)

when:
loginPage.go()
loginPage.login(TEST_USER, TEST_PASS)
page(ProjectListPage).waitUntilPageLoaded()
projectHomePage.goProjectHome(projectName)
editNodesPage.go()
editNodesPage.waitUntilPageLoaded()
editNodesFilePage.go()
editNodesFilePage.waitUntilPageLoaded()
editNodesFilePage.waitForAceToRender()
def linesInAceGutter = editNodesFilePage.aceGutterElement().getText()
List<String> linesAsList = Arrays.stream(linesInAceGutter.split("\\n"))
.collect(Collectors.toList());

then:
linesAsList.size() > 1

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.rundeck.tests.functional.selenium.pages

import org.openqa.selenium.By
import org.openqa.selenium.WebElement
import org.openqa.selenium.support.ui.ExpectedConditions
import org.openqa.selenium.support.ui.WebDriverWait
import org.rundeck.util.container.SeleniumContext

import java.time.Duration

class EditNodesFilePage extends BasePage{

static final String PAGE_PATH = "/nodes/source"
static final String editSuffix = "edit"
int index
String project

By aceEditorGutter = By.className("ace_gutter")

/**
* Create a new page
* @param context
*/
EditNodesFilePage(SeleniumContext context) {
super(context)
}

@Override
String getLoadPath() {
if(!project){
throw new IllegalStateException("project is not set, cannot load nodes.")
}
if( !index ){
throw new IllegalStateException("No node index specified, cannot load node file edit page.")
}
return "/project/${project}${PAGE_PATH}/${index}/${editSuffix}"
}

void waitForAceToRender(){
new WebDriverWait(driver, Duration.ofSeconds(30)).until(
ExpectedConditions.visibilityOf(aceGutterElement())
)
}

WebElement aceGutterElement(){
el aceEditorGutter
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.rundeck.tests.functional.selenium.pages

import org.openqa.selenium.By
import org.openqa.selenium.WebElement
import org.rundeck.util.container.SeleniumContext

class EditNodesPage extends BasePage{

static final String PAGE_PATH = "/nodes/sources"
String project

/**
* Create a new page
* @param context
*/
EditNodesPage(SeleniumContext context) {
super(context)
}

@Override
String getLoadPath() {
if(!project){
throw new IllegalStateException("project is not set, cannot load nodes.")
}
return "/project/${project}${PAGE_PATH}"
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ abstract class BaseContainer extends Specification implements ClientProvider {
}
}

void setupProjectWithNodes(String name, String projectImportLocation) {
def getProject = client.doGet("/project/${name}")
if (getProject.code() == 404) {
def post = client.doPost("/projects", [name: name])
if (!post.successful) {
throw new RuntimeException("Failed to create project: ${post.body().string()}")
}
client.doPut("/project/${name}/import?importConfig=true&importACL=true&importNodesSources=true", new File(getClass().getResource(projectImportLocation).getPath()))
}else if(getProject.code() == 200){
client.doPut("/project/${name}/import?importConfig=true&importACL=true&importNodesSources=true", new File(getClass().getResource(projectImportLocation).getPath()))
}
}

RdClient _client
@Override
RdClient getClient() {
Expand Down Expand Up @@ -145,4 +158,5 @@ abstract class BaseContainer extends Specification implements ClientProvider {
def setupSpec() {
startEnvironment()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ services:
- "/etc/localtime:/etc/localtime:ro"
- "/etc/timezone:/etc/timezone:ro"
- "../../../tokens.properties:/home/rundeck/server/config/tokens.properties"
- "../../../realm.properties:/home/rundeck/server/config/realm.properties"
- "../../../realm.properties:/home/rundeck/server/config/realm.properties"
- "../../../resource-model:/home/rundeck/server/config/resource-model"
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"test-node": {
"nodename": "test-node",
"customEnv": "test",
"hostname": "http://localhost:4443",
"editUrl": "http://localhost:4443",
"customIdx": "01",
"osFamily": "Linux",
"username": "rundeck",
"tags": "test"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ export default defineComponent({
return {
editor: undefined as undefined | ace.Ace.Editor,
contentBackup: "",
observer: undefined as undefined | MutationObserver
observer: undefined as undefined | MutationObserver,
jsonSpaces: 2 as number
}
},
watch: {
modelValue: function(val): void {
if (this.contentBackup !== val) {
// @ts-ignore
this.editor!.session.setValue(val,1)
this.contentBackup = val
this.editor!.getSession().setValue(this.resolveValue(val) ,1)
this.contentBackup = this.resolveValue(val)
this.attachChangeEventToEditor()
}
},
theme: function (newTheme): void {
Expand Down Expand Up @@ -79,15 +81,9 @@ export default defineComponent({
editor.setTheme(this.resolveTheme(theme))

if (this.modelValue)
editor.setValue(this.modelValue, 1)
editor.setValue(this.resolveValue(this.modelValue), 1)

this.contentBackup = this.modelValue

editor.on('change', () => {
const content = editor.getValue()
this.$emit('update:modelValue', content)
this.contentBackup = content
})

if (this.options)
editor.setOptions(this.options)
Expand Down Expand Up @@ -149,6 +145,29 @@ export default defineComponent({
},
resolveLang(lang: string): string {
return typeof lang === 'string' ? `ace/mode/${lang}` : lang
},
/**
* Convert value to supported format
*
* @param val
*/
resolveValue(val: string){
const LANG_JSON: String = 'json'
if( this.lang == LANG_JSON ){
return JSON.stringify(JSON.parse(val), null, this.jsonSpaces)
}
return val
},
/**
* Attach change event to ace editor
*
*/
attachChangeEventToEditor(): void{
this.editor!.on('change', () => {
const content = this.editor!.getValue()
this.$emit('update:modelValue', content)
this.contentBackup = content
})
}
}
})
Expand Down