Skip to content

Conversation

cdifino
Copy link

@cdifino cdifino commented Sep 21, 2019

@cdifino
Copy link
Author

cdifino commented Sep 21, 2019

Hello @corevo here is the modifications I have done for the connected mode feature.
Here is how it currently works:
If it is in connected mode and we want to interact with Selenium IDE, it will always need to match the connection id. If it is not in connected mode, there is no need to pass a connection ID in the payload and everything should work fine.
The only way to create another connection is by calling "connect with the new connection id"
When connecting to a new extension it will prompt the user is he/she wants to connect.
If extension wants to load project to Selenium IDE, and the user has unsaved changes, it will prompt the user to save files or just load. This will happen if there is a connection or not.
If you need an extension to test these changes I made this little extension.
ext.zip

pauseNotificationSent = false
@observable
isControlledBy = {
connectionId: null,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why we need connectionId we can use the extensionId instead.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to make it more flexible to the user, if there are multiple instance within the same extension ID you want the user to be able to control what instance is talking to Selenium IDE.


router.post('/register', (req, res) => {
if (req.connectionId != UiState.isControlledBy.connectionId)
throw new Error('Another connection is established')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can register other plugins, we should just block requests to /control so only one can control it, thoughts?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the idea is to block everything but /control. When Selenium is controlled by a specific extension, no other extension should be listening to events for security purposes. On the other hand, the only way to interrupt the connection is to request control through the /control call. If the user accepts to change the connection, the new extension will have control, and all the plugins will be unplugged.

})
router.post(
'/register',
controlledOnly((req, res) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should only block other extensions from calling /control right?

If the extension is in controlled mode, other plugins should still work, what do you think?

Connected Mode Implementation

Fixed check for connection ID bug

Fixed prettier bug and changed description of pop up

Fixed prettier bug

Fixed prettier bug

Plugin Manager Fix, modified dialog, window focus addition

Closure

Prettier

Prettier

Prettier

Restart to welcome sccreen when entering connected mode

Prettier

Prettier

Prettier

Prettier

Prettier

Prettier

Prettier

debug travis fail

restart capabiulity everytime is starting a connection

prettier

travis bugs

travis bugs
Copy link

@melode11 melode11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had concern of the selenium IDE's extension id. For now third party plugin need to use a hardcoded string as extension id to send message to Selenium IDE. Selenium IDE's extension id could change when manifest file changes. Shall we have a way of storing the extension id to a special key in local storage whenever the IDE extension's background or contentScript is executed. So third party extension can look for that key to always get the right extension id.
@corevo Thoughts?


const router = new Router()

const controlledOnly = apiFn => {

This comment was marked as resolved.

if (
(Manager.controller &&
Manager.controller.connectionId != req.connectionId) ||
!Manager.controller

This comment was marked as resolved.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when manager.controller is undefined it only means that there is no assisted control yet. This scenario is directed to the case when there is a connected mode but the connection id is a different one or when there is not connected mode and there is a potential for connecting.

if (
message.control &&
message.controller.connectionId &&
message.controller.id

This comment was marked as resolved.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the senders. Thant is how the plugin manifesto works. The sender (or extension Id) turn out to be the plugin id.

nbansal1993 and others added 3 commits October 8, 2019 15:43
Connected Mode Implementation

Fixed check for connection ID bug

Fixed prettier bug and changed description of pop up

Fixed prettier bug

Fixed prettier bug

Plugin Manager Fix, modified dialog, window focus addition

Closure

Prettier

Prettier

Prettier

Restart to welcome sccreen when entering connected mode

Prettier

Prettier

Prettier

Prettier

Prettier

Prettier

Prettier

debug travis fail

restart capabiulity everytime is starting a connection

prettier

travis bugs

travis bugs

documentation of connected mode

deleted end connection
@melode11
Copy link

melode11 commented Oct 9, 2019

All the changes are done in our side. current state of the connected Mode PR is thoroughly tested by our testing team, including 10+ different corner cases are covered and all work as expected.

Copy link
Member

@corevo corevo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good & clean.

let payload = message.payload

payload.sender = sender.id
if (message.uri === '/_connect' || message.uri === '/_close') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could have an internal API that starts with /private instead of prefixing with _.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds good. I will do these changes and push them to PR

} else if (UiState.isControlled) {
return (
<div className="connected-mode">
<div className="connected-mode">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why both divs have the same class attached?
Also controlled-banner instead of connected-mode.

This comment was marked as resolved.

return this.plugins.find(p => p.id === pluginId)
}

unregisterAllPlugins() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary

Fixed.

```
### `POST /control`

Start a connection with a specific connection Id from another chrome extension. When this connection is accepted by the user, Selenium IDE restarts and registers the caller, and the extension takes exclusive control of Selenium IDE until user closes Selenium IDE or another connection is accepted. When this mode is on, the save to computer functionality gets overritten by sending the side file to the extension controlling Selenium IDE. When in this mode, the user needs to add connectionId variable to make other API calls such as `POST /project`, `GET /project`, `POST /log`, `POST /register`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use connectionId instead of using the controller extension ID? seems less secure since this is a user-generated token rather than a browser secure token.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, we can switch to use sender id.

},
}

function checkControl(req) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function name is very ambiguous.

The function returns true in 2 cases

  • Extension is not controlled by anyone
  • Extension is controlled, and the request is sent by the controller

While returning false in 1 case

  • Extension is controlled by someone else

So I think we should split this function (and the decorator) into two that would be more readable
isControlled - would return true/false if the IDE is under control of any extension
isControlledByThisExtension - would return true only if the current extension is the controller

Then we can compose the decorators.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I can make the name to be more clear. Split to more decorators sounds OK but we are never going to used the sparated decorators in other places. So rather keep it in a single function to simply the call hierarchy. Is that make sense?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it is hard to think a good name for it. I'll just do split.

conflictAction: 'overwrite',
})
return UiState.isControlled
? Promise.resolve()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not silently fail, we should send a message to the controller that the user requested to save.

Look at PlaybackState to get an idea of how to send an event over to an extension.

I was thinking of something like:

{
      action: 'event',
      event: 'saveProject',
      options: {
        project
      }
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already send the plugin with the emit of the project entity. Do we expect to send another event here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emit project is something else, in controlled mode we shouldn't emit to begin with.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So to clarify.
You want in control mode, IDE will send a saveProject event, do you still want to keep the emit? I guess we should still keep it for consistency between control and non-control mode?

delete payload.restart

const newMessage = {
uri: '/privateConnect',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant /private/connect and use the /private/ prefix in general for internal IDE messages.

Also keep things lower cased.

changing private apis to /private/

sending project in message on save
@corevo corevo merged commit 42c79a2 into SeleniumHQ:v3 Oct 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants